Commit a8c617ea authored by David S. Miller's avatar David S. Miller
parents 2307f866 c6ba68a2
......@@ -487,17 +487,17 @@ typedef enum {
*
* Value Cause Code
* --------- ----------------
* 0x0100 Request to Delete Last Remaining IP Address.
* 0x0101 Operation Refused Due to Resource Shortage.
* 0x0102 Request to Delete Source IP Address.
* 0x0103 Association Aborted due to illegal ASCONF-ACK
* 0x0104 Request refused - no authorization.
* 0x00A0 Request to Delete Last Remaining IP Address.
* 0x00A1 Operation Refused Due to Resource Shortage.
* 0x00A2 Request to Delete Source IP Address.
* 0x00A3 Association Aborted due to illegal ASCONF-ACK
* 0x00A4 Request refused - no authorization.
*/
SCTP_ERROR_DEL_LAST_IP = cpu_to_be16(0x0100),
SCTP_ERROR_RSRC_LOW = cpu_to_be16(0x0101),
SCTP_ERROR_DEL_SRC_IP = cpu_to_be16(0x0102),
SCTP_ERROR_ASCONF_ACK = cpu_to_be16(0x0103),
SCTP_ERROR_REQ_REFUSED = cpu_to_be16(0x0104),
SCTP_ERROR_DEL_LAST_IP = cpu_to_be16(0x00A0),
SCTP_ERROR_RSRC_LOW = cpu_to_be16(0x00A1),
SCTP_ERROR_DEL_SRC_IP = cpu_to_be16(0x00A2),
SCTP_ERROR_ASCONF_ACK = cpu_to_be16(0x00A3),
SCTP_ERROR_REQ_REFUSED = cpu_to_be16(0x00A4),
/* AUTH Section 4. New Error Cause
*
......
......@@ -1939,10 +1939,8 @@ void sctp_association_free(struct sctp_association *);
void sctp_association_put(struct sctp_association *);
void sctp_association_hold(struct sctp_association *);
struct sctp_transport *sctp_assoc_choose_init_transport(
struct sctp_association *);
struct sctp_transport *sctp_assoc_choose_shutdown_transport(
struct sctp_association *);
struct sctp_transport *sctp_assoc_choose_alter_transport(
struct sctp_association *, struct sctp_transport *);
void sctp_assoc_update_retran_path(struct sctp_association *);
struct sctp_transport *sctp_assoc_lookup_paddr(const struct sctp_association *,
const union sctp_addr *);
......
......@@ -147,6 +147,8 @@ enum sctp_optname {
#define SCTP_GET_LOCAL_ADDRS SCTP_GET_LOCAL_ADDRS
SCTP_SOCKOPT_CONNECTX, /* CONNECTX requests. */
#define SCTP_SOCKOPT_CONNECTX SCTP_SOCKOPT_CONNECTX
SCTP_SOCKOPT_CONNECTX3, /* CONNECTX requests. (new implementation) */
#define SCTP_SOCKOPT_CONNECTX3 SCTP_SOCKOPT_CONNECTX3
};
/*
......
......@@ -293,6 +293,7 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a
* told otherwise.
*/
asoc->peer.ipv4_address = 1;
if (asoc->base.sk->sk_family == PF_INET6)
asoc->peer.ipv6_address = 1;
INIT_LIST_HEAD(&asoc->asocs);
......@@ -566,6 +567,21 @@ void sctp_assoc_rm_peer(struct sctp_association *asoc,
if (asoc->init_last_sent_to == peer)
asoc->init_last_sent_to = NULL;
/* If we remove the transport an SHUTDOWN was last sent to, set it
* to NULL. Combined with the update of the retran path above, this
* will cause the next SHUTDOWN to be sent to the next available
* transport, maintaining the cycle.
*/
if (asoc->shutdown_last_sent_to == peer)
asoc->shutdown_last_sent_to = NULL;
/* If we remove the transport an ASCONF was last sent to, set it to
* NULL.
*/
if (asoc->addip_last_asconf &&
asoc->addip_last_asconf->transport == peer)
asoc->addip_last_asconf->transport = NULL;
asoc->peer.transport_count--;
sctp_transport_free(peer);
......@@ -1268,49 +1284,21 @@ void sctp_assoc_update_retran_path(struct sctp_association *asoc)
ntohs(t->ipaddr.v4.sin_port));
}
/* Choose the transport for sending a INIT packet. */
struct sctp_transport *sctp_assoc_choose_init_transport(
struct sctp_association *asoc)
{
struct sctp_transport *t;
/* Use the retran path. If the last INIT was sent over the
* retran path, update the retran path and use it.
*/
if (!asoc->init_last_sent_to) {
t = asoc->peer.active_path;
} else {
if (asoc->init_last_sent_to == asoc->peer.retran_path)
sctp_assoc_update_retran_path(asoc);
t = asoc->peer.retran_path;
}
SCTP_DEBUG_PRINTK_IPADDR("sctp_assoc_update_retran_path:association"
" %p addr: ",
" port: %d\n",
asoc,
(&t->ipaddr),
ntohs(t->ipaddr.v4.sin_port));
return t;
}
/* Choose the transport for sending a SHUTDOWN packet. */
struct sctp_transport *sctp_assoc_choose_shutdown_transport(
struct sctp_association *asoc)
/* Choose the transport for sending retransmit packet. */
struct sctp_transport *sctp_assoc_choose_alter_transport(
struct sctp_association *asoc, struct sctp_transport *last_sent_to)
{
/* If this is the first time SHUTDOWN is sent, use the active path,
* else use the retran path. If the last SHUTDOWN was sent over the
/* If this is the first time packet is sent, use the active path,
* else use the retran path. If the last packet was sent over the
* retran path, update the retran path and use it.
*/
if (!asoc->shutdown_last_sent_to)
if (!last_sent_to)
return asoc->peer.active_path;
else {
if (asoc->shutdown_last_sent_to == asoc->peer.retran_path)
if (last_sent_to == asoc->peer.retran_path)
sctp_assoc_update_retran_path(asoc);
return asoc->peer.retran_path;
}
}
/* Update the association's pmtu and frag_point by going through all the
......@@ -1482,6 +1470,10 @@ int sctp_assoc_set_id(struct sctp_association *asoc, gfp_t gfp)
{
int assoc_id;
int error = 0;
/* If the id is already assigned, keep it. */
if (asoc->assoc_id)
return error;
retry:
if (unlikely(!idr_pre_get(&sctp_assocs_id, gfp)))
return -ENOMEM;
......
......@@ -2864,19 +2864,19 @@ static __be16 sctp_process_asconf_param(struct sctp_association *asoc,
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);
......@@ -2886,7 +2886,7 @@ static __be16 sctp_process_asconf_param(struct sctp_association *asoc,
* 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:
......@@ -2954,12 +2954,12 @@ static __be16 sctp_process_asconf_param(struct sctp_association *asoc,
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;
return SCTP_ERROR_UNKNOWN_PARAM;
break;
}
......@@ -3273,7 +3273,7 @@ int sctp_process_asconf_ack(struct sctp_association *asoc,
retval = 1;
break;
case SCTP_ERROR_INV_PARAM:
case SCTP_ERROR_UNKNOWN_PARAM:
/* Disable sending this type of asconf parameter in
* future.
*/
......
......@@ -686,7 +686,8 @@ static void sctp_cmd_setup_t2(sctp_cmd_seq_t *cmds,
{
struct sctp_transport *t;
t = sctp_assoc_choose_shutdown_transport(asoc);
t = sctp_assoc_choose_alter_transport(asoc,
asoc->shutdown_last_sent_to);
asoc->shutdown_last_sent_to = t;
asoc->timeouts[SCTP_EVENT_TIMEOUT_T2_SHUTDOWN] = t->rto;
chunk->transport = t;
......@@ -777,7 +778,7 @@ static void sctp_cmd_setup_t4(sctp_cmd_seq_t *cmds,
{
struct sctp_transport *t;
t = asoc->peer.active_path;
t = sctp_assoc_choose_alter_transport(asoc, chunk->transport);
asoc->timeouts[SCTP_EVENT_TIMEOUT_T4_RTO] = t->rto;
chunk->transport = t;
}
......@@ -1379,7 +1380,8 @@ static int sctp_cmd_interpreter(sctp_event_t event_type,
case SCTP_CMD_INIT_CHOOSE_TRANSPORT:
chunk = cmd->obj.ptr;
t = sctp_assoc_choose_init_transport(asoc);
t = sctp_assoc_choose_alter_transport(asoc,
asoc->init_last_sent_to);
asoc->init_last_sent_to = t;
chunk->transport = t;
t->init_sent_count++;
......
......@@ -5432,7 +5432,11 @@ sctp_disposition_t sctp_sf_t2_timer_expire(const struct sctp_endpoint *ep,
if (!reply)
goto nomem;
/* Do some failure management (Section 8.2). */
/* Do some failure management (Section 8.2).
* If we remove the transport an SHUTDOWN was last sent to, don't
* do failure management.
*/
if (asoc->shutdown_last_sent_to)
sctp_add_cmd_sf(commands, SCTP_CMD_STRIKE,
SCTP_TRANSPORT(asoc->shutdown_last_sent_to));
......@@ -5471,7 +5475,9 @@ sctp_disposition_t sctp_sf_t4_timer_expire(
* detection on the appropriate destination address as defined in
* RFC2960 [5] section 8.1 and 8.2.
*/
sctp_add_cmd_sf(commands, SCTP_CMD_STRIKE, SCTP_TRANSPORT(transport));
if (transport)
sctp_add_cmd_sf(commands, SCTP_CMD_STRIKE,
SCTP_TRANSPORT(transport));
/* Reconfig T4 timer and transport. */
sctp_add_cmd_sf(commands, SCTP_CMD_SETUP_T4, SCTP_CHUNK(chunk));
......
......@@ -698,7 +698,7 @@ chunk_event_table_unknown[SCTP_STATE_NUM_STATES] = {
TYPE_SCTP_FUNC(sctp_sf_do_prm_asconf), \
/* SCTP_STATE_SHUTDOWN_ACK_SENT */ \
TYPE_SCTP_FUNC(sctp_sf_error_shutdown), \
} /* TYPE_SCTP_PRIMITIVE_REQUESTHEARTBEAT */
} /* TYPE_SCTP_PRIMITIVE_ASCONF */
/* The primary index for this table is the primitive type.
* The secondary index for this table is the state.
......
......@@ -1100,6 +1100,15 @@ static int __sctp_connect(struct sock* sk,
goto out_free;
}
/* In case the user of sctp_connectx() wants an association
* id back, assign one now.
*/
if (assoc_id) {
err = sctp_assoc_set_id(asoc, GFP_KERNEL);
if (err < 0)
goto out_free;
}
err = sctp_primitive_ASSOCIATE(asoc, NULL);
if (err < 0) {
goto out_free;
......@@ -1120,7 +1129,7 @@ static int __sctp_connect(struct sock* sk,
timeo = sock_sndtimeo(sk, f_flags & O_NONBLOCK);
err = sctp_wait_for_connect(asoc, &timeo);
if (!err && assoc_id)
if ((err == 0 || err == -EINPROGRESS) && assoc_id)
*assoc_id = asoc->assoc_id;
/* Don't free association on exit. */
......@@ -1264,6 +1273,34 @@ SCTP_STATIC int sctp_setsockopt_connectx(struct sock* sk,
return assoc_id;
}
/*
* New (hopefully final) interface for the API. The option buffer is used
* both for the returned association id and the addresses.
*/
SCTP_STATIC int sctp_getsockopt_connectx3(struct sock* sk, int len,
char __user *optval,
int __user *optlen)
{
sctp_assoc_t assoc_id = 0;
int err = 0;
if (len < sizeof(assoc_id))
return -EINVAL;
err = __sctp_setsockopt_connectx(sk,
(struct sockaddr __user *)(optval + sizeof(assoc_id)),
len - sizeof(assoc_id), &assoc_id);
if (err == 0 || err == -EINPROGRESS) {
if (copy_to_user(optval, &assoc_id, sizeof(assoc_id)))
return -EFAULT;
if (put_user(sizeof(assoc_id), optlen))
return -EFAULT;
}
return err;
}
/* API 3.1.4 close() - UDP Style Syntax
* Applications use close() to perform graceful shutdown (as described in
* Section 10.1 of [SCTP]) on ALL the associations currently represented
......@@ -5578,6 +5615,9 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname,
retval = sctp_getsockopt_local_addrs(sk, len, optval,
optlen);
break;
case SCTP_SOCKOPT_CONNECTX3:
retval = sctp_getsockopt_connectx3(sk, len, optval, optlen);
break;
case SCTP_DEFAULT_SEND_PARAM:
retval = sctp_getsockopt_default_send_param(sk, len,
optval, optlen);
......
......@@ -49,8 +49,8 @@ static int zero = 0;
static int one = 1;
static int timer_max = 86400000; /* ms in one day */
static int int_max = INT_MAX;
static long sack_timer_min = 1;
static long sack_timer_max = 500;
static int sack_timer_min = 1;
static int sack_timer_max = 500;
extern int sysctl_sctp_mem[3];
extern int sysctl_sctp_rmem[3];
......@@ -223,7 +223,7 @@ static ctl_table sctp_table[] = {
.ctl_name = NET_SCTP_SACK_TIMEOUT,
.procname = "sack_timeout",
.data = &sctp_sack_timeout,
.maxlen = sizeof(long),
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = proc_dointvec_minmax,
.strategy = sysctl_intvec,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment