#include <linux/inet.h>
#include <linux/scatterlist.h>
#include <linux/crypto.h>
+#include <linux/slab.h>
#include <net/sock.h>
#include <linux/skbuff.h>
target = skb_put(chunk->skb, len);
- memcpy(target, data, len);
+ if (data)
+ memcpy(target, data, len);
+ else
+ memset(target, 0, len);
/* Adjust the chunk length field. */
chunk->chunk_hdr->length = htons(chunklen + len);
struct sctp_chunk *sctp_make_op_error(const struct sctp_association *asoc,
const struct sctp_chunk *chunk,
__be16 cause_code, const void *payload,
- size_t paylen)
+ size_t paylen, size_t reserve_tail)
{
struct sctp_chunk *retval;
- retval = sctp_make_op_error_space(asoc, chunk, paylen);
+ retval = sctp_make_op_error_space(asoc, chunk, paylen + reserve_tail);
if (!retval)
goto nodata;
- sctp_init_cause(retval, cause_code, paylen);
+ sctp_init_cause(retval, cause_code, paylen + reserve_tail);
sctp_addto_chunk(retval, paylen, payload);
+ if (reserve_tail)
+ sctp_addto_param(retval, reserve_tail, NULL);
nodata:
return retval;
addr_param = (union sctp_addr_param *)
((void *)asconf_param + sizeof(sctp_addip_param_t));
+ if (asconf_param->param_hdr.type != SCTP_PARAM_ADD_IP &&
+ asconf_param->param_hdr.type != SCTP_PARAM_DEL_IP &&
+ asconf_param->param_hdr.type != SCTP_PARAM_SET_PRIMARY)
+ return SCTP_ERROR_UNKNOWN_PARAM;
+
switch (addr_param->v4.param_hdr.type) {
case SCTP_PARAM_IPV6_ADDRESS:
if (!asoc->peer.ipv6_address)
- return SCTP_ERROR_INV_PARAM;
+ return SCTP_ERROR_DNS_FAILED;
break;
case SCTP_PARAM_IPV4_ADDRESS:
if (!asoc->peer.ipv4_address)
- return SCTP_ERROR_INV_PARAM;
+ return SCTP_ERROR_DNS_FAILED;
break;
default:
- return SCTP_ERROR_INV_PARAM;
+ return SCTP_ERROR_DNS_FAILED;
}
af = sctp_get_af_specific(param_type2af(addr_param->v4.param_hdr.type));
if (unlikely(!af))
- return SCTP_ERROR_INV_PARAM;
+ return SCTP_ERROR_DNS_FAILED;
af->from_addr_param(&addr, addr_param, htons(asoc->peer.port), 0);
* make sure we check for that)
*/
if (!af->is_any(&addr) && !af->addr_valid(&addr, NULL, asconf->skb))
- return SCTP_ERROR_INV_PARAM;
+ return SCTP_ERROR_DNS_FAILED;
switch (asconf_param->param_hdr.type) {
case SCTP_PARAM_ADD_IP:
peer = sctp_assoc_lookup_paddr(asoc, &addr);
if (!peer)
- return SCTP_ERROR_INV_PARAM;
+ return SCTP_ERROR_DNS_FAILED;
sctp_assoc_set_primary(asoc, peer);
break;
- default:
- return SCTP_ERROR_INV_PARAM;
- break;
}
return SCTP_ERROR_NO_ERROR;
}
/* Process a asconf parameter that is successfully acked. */
-static int sctp_asconf_param_success(struct sctp_association *asoc,
+static void sctp_asconf_param_success(struct sctp_association *asoc,
sctp_addip_param_t *asconf_param)
{
struct sctp_af *af;
union sctp_addr_param *addr_param;
struct sctp_transport *transport;
struct sctp_sockaddr_entry *saddr;
- int retval = 0;
addr_param = (union sctp_addr_param *)
((void *)asconf_param + sizeof(sctp_addip_param_t));
saddr->state = SCTP_ADDR_SRC;
}
local_bh_enable();
+ list_for_each_entry(transport, &asoc->peer.transport_addr_list,
+ transports) {
+ if (transport->state == SCTP_ACTIVE)
+ continue;
+ dst_release(transport->dst);
+ sctp_transport_route(transport, NULL,
+ sctp_sk(asoc->base.sk));
+ }
break;
case SCTP_PARAM_DEL_IP:
local_bh_disable();
- retval = sctp_del_bind_addr(bp, &addr);
+ sctp_del_bind_addr(bp, &addr);
local_bh_enable();
list_for_each_entry(transport, &asoc->peer.transport_addr_list,
transports) {
default:
break;
}
-
- return retval;
}
/* Get the corresponding ASCONF response error code from the ASCONF_ACK chunk
switch (err_code) {
case SCTP_ERROR_NO_ERROR:
- retval = sctp_asconf_param_success(asoc, asconf_param);
+ sctp_asconf_param_success(asoc, asconf_param);
break;
case SCTP_ERROR_RSRC_LOW:
retval = 1;
break;
- case SCTP_ERROR_INV_PARAM:
+ case SCTP_ERROR_UNKNOWN_PARAM:
/* Disable sending this type of asconf parameter in
* future.
*/