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