Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6
This commit is contained in:
@@ -1194,8 +1194,10 @@ void sctp_assoc_update(struct sctp_association *asoc,
|
||||
/* Remove any peer addresses not present in the new association. */
|
||||
list_for_each_safe(pos, temp, &asoc->peer.transport_addr_list) {
|
||||
trans = list_entry(pos, struct sctp_transport, transports);
|
||||
if (!sctp_assoc_lookup_paddr(new, &trans->ipaddr))
|
||||
sctp_assoc_del_peer(asoc, &trans->ipaddr);
|
||||
if (!sctp_assoc_lookup_paddr(new, &trans->ipaddr)) {
|
||||
sctp_assoc_rm_peer(asoc, trans);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (asoc->state >= SCTP_STATE_ESTABLISHED)
|
||||
sctp_transport_reset(trans);
|
||||
|
@@ -144,6 +144,7 @@ static struct sctp_endpoint *sctp_endpoint_init(struct sctp_endpoint *ep,
|
||||
/* Use SCTP specific send buffer space queues. */
|
||||
ep->sndbuf_policy = sctp_sndbuf_policy;
|
||||
|
||||
sk->sk_data_ready = sctp_data_ready;
|
||||
sk->sk_write_space = sctp_write_space;
|
||||
sock_set_flag(sk, SOCK_USE_WRITE_QUEUE);
|
||||
|
||||
|
@@ -108,7 +108,7 @@ static const struct sctp_paramhdr prsctp_param = {
|
||||
cpu_to_be16(sizeof(struct sctp_paramhdr)),
|
||||
};
|
||||
|
||||
/* A helper to initialize to initialize an op error inside a
|
||||
/* A helper to initialize an op error inside a
|
||||
* provided chunk, as most cause codes will be embedded inside an
|
||||
* abort chunk.
|
||||
*/
|
||||
@@ -125,6 +125,29 @@ void sctp_init_cause(struct sctp_chunk *chunk, __be16 cause_code,
|
||||
chunk->subh.err_hdr = sctp_addto_chunk(chunk, sizeof(sctp_errhdr_t), &err);
|
||||
}
|
||||
|
||||
/* A helper to initialize an op error inside a
|
||||
* provided chunk, as most cause codes will be embedded inside an
|
||||
* abort chunk. Differs from sctp_init_cause in that it won't oops
|
||||
* if there isn't enough space in the op error chunk
|
||||
*/
|
||||
int sctp_init_cause_fixed(struct sctp_chunk *chunk, __be16 cause_code,
|
||||
size_t paylen)
|
||||
{
|
||||
sctp_errhdr_t err;
|
||||
__u16 len;
|
||||
|
||||
/* Cause code constants are now defined in network order. */
|
||||
err.cause = cause_code;
|
||||
len = sizeof(sctp_errhdr_t) + paylen;
|
||||
err.length = htons(len);
|
||||
|
||||
if (skb_tailroom(chunk->skb) > len)
|
||||
return -ENOSPC;
|
||||
chunk->subh.err_hdr = sctp_addto_chunk_fixed(chunk,
|
||||
sizeof(sctp_errhdr_t),
|
||||
&err);
|
||||
return 0;
|
||||
}
|
||||
/* 3.3.2 Initiation (INIT) (1)
|
||||
*
|
||||
* This chunk is used to initiate a SCTP association between two
|
||||
@@ -208,7 +231,8 @@ struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc,
|
||||
sp = sctp_sk(asoc->base.sk);
|
||||
num_types = sp->pf->supported_addrs(sp, types);
|
||||
|
||||
chunksize = sizeof(init) + addrs_len + SCTP_SAT_LEN(num_types);
|
||||
chunksize = sizeof(init) + addrs_len;
|
||||
chunksize += WORD_ROUND(SCTP_SAT_LEN(num_types));
|
||||
chunksize += sizeof(ecap_param);
|
||||
|
||||
if (sctp_prsctp_enable)
|
||||
@@ -238,14 +262,14 @@ struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc,
|
||||
/* Add HMACS parameter length if any were defined */
|
||||
auth_hmacs = (sctp_paramhdr_t *)asoc->c.auth_hmacs;
|
||||
if (auth_hmacs->length)
|
||||
chunksize += ntohs(auth_hmacs->length);
|
||||
chunksize += WORD_ROUND(ntohs(auth_hmacs->length));
|
||||
else
|
||||
auth_hmacs = NULL;
|
||||
|
||||
/* Add CHUNKS parameter length */
|
||||
auth_chunks = (sctp_paramhdr_t *)asoc->c.auth_chunks;
|
||||
if (auth_chunks->length)
|
||||
chunksize += ntohs(auth_chunks->length);
|
||||
chunksize += WORD_ROUND(ntohs(auth_chunks->length));
|
||||
else
|
||||
auth_chunks = NULL;
|
||||
|
||||
@@ -255,7 +279,8 @@ struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc,
|
||||
|
||||
/* If we have any extensions to report, account for that */
|
||||
if (num_ext)
|
||||
chunksize += sizeof(sctp_supported_ext_param_t) + num_ext;
|
||||
chunksize += WORD_ROUND(sizeof(sctp_supported_ext_param_t) +
|
||||
num_ext);
|
||||
|
||||
/* RFC 2960 3.3.2 Initiation (INIT) (1)
|
||||
*
|
||||
@@ -397,13 +422,13 @@ struct sctp_chunk *sctp_make_init_ack(const struct sctp_association *asoc,
|
||||
|
||||
auth_hmacs = (sctp_paramhdr_t *)asoc->c.auth_hmacs;
|
||||
if (auth_hmacs->length)
|
||||
chunksize += ntohs(auth_hmacs->length);
|
||||
chunksize += WORD_ROUND(ntohs(auth_hmacs->length));
|
||||
else
|
||||
auth_hmacs = NULL;
|
||||
|
||||
auth_chunks = (sctp_paramhdr_t *)asoc->c.auth_chunks;
|
||||
if (auth_chunks->length)
|
||||
chunksize += ntohs(auth_chunks->length);
|
||||
chunksize += WORD_ROUND(ntohs(auth_chunks->length));
|
||||
else
|
||||
auth_chunks = NULL;
|
||||
|
||||
@@ -412,7 +437,8 @@ struct sctp_chunk *sctp_make_init_ack(const struct sctp_association *asoc,
|
||||
}
|
||||
|
||||
if (num_ext)
|
||||
chunksize += sizeof(sctp_supported_ext_param_t) + num_ext;
|
||||
chunksize += WORD_ROUND(sizeof(sctp_supported_ext_param_t) +
|
||||
num_ext);
|
||||
|
||||
/* Now allocate and fill out the chunk. */
|
||||
retval = sctp_make_chunk(asoc, SCTP_CID_INIT_ACK, 0, chunksize);
|
||||
@@ -1129,6 +1155,24 @@ nodata:
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* Create an Operation Error chunk of a fixed size,
|
||||
* specifically, max(asoc->pathmtu, SCTP_DEFAULT_MAXSEGMENT)
|
||||
* This is a helper function to allocate an error chunk for
|
||||
* for those invalid parameter codes in which we may not want
|
||||
* to report all the errors, if the incomming chunk is large
|
||||
*/
|
||||
static inline struct sctp_chunk *sctp_make_op_error_fixed(
|
||||
const struct sctp_association *asoc,
|
||||
const struct sctp_chunk *chunk)
|
||||
{
|
||||
size_t size = asoc ? asoc->pathmtu : 0;
|
||||
|
||||
if (!size)
|
||||
size = SCTP_DEFAULT_MAXSEGMENT;
|
||||
|
||||
return sctp_make_op_error_space(asoc, chunk, size);
|
||||
}
|
||||
|
||||
/* Create an Operation Error chunk. */
|
||||
struct sctp_chunk *sctp_make_op_error(const struct sctp_association *asoc,
|
||||
const struct sctp_chunk *chunk,
|
||||
@@ -1371,6 +1415,18 @@ void *sctp_addto_chunk(struct sctp_chunk *chunk, int len, const void *data)
|
||||
return target;
|
||||
}
|
||||
|
||||
/* Append bytes to the end of a chunk. Returns NULL if there isn't sufficient
|
||||
* space in the chunk
|
||||
*/
|
||||
void *sctp_addto_chunk_fixed(struct sctp_chunk *chunk,
|
||||
int len, const void *data)
|
||||
{
|
||||
if (skb_tailroom(chunk->skb) > len)
|
||||
return sctp_addto_chunk(chunk, len, data);
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Append bytes from user space to the end of a chunk. Will panic if
|
||||
* chunk is not big enough.
|
||||
* Returns a kernel err value.
|
||||
@@ -1974,13 +2030,12 @@ static sctp_ierror_t sctp_process_unk_param(const struct sctp_association *asoc,
|
||||
* returning multiple unknown parameters.
|
||||
*/
|
||||
if (NULL == *errp)
|
||||
*errp = sctp_make_op_error_space(asoc, chunk,
|
||||
ntohs(chunk->chunk_hdr->length));
|
||||
*errp = sctp_make_op_error_fixed(asoc, chunk);
|
||||
|
||||
if (*errp) {
|
||||
sctp_init_cause(*errp, SCTP_ERROR_UNKNOWN_PARAM,
|
||||
sctp_init_cause_fixed(*errp, SCTP_ERROR_UNKNOWN_PARAM,
|
||||
WORD_ROUND(ntohs(param.p->length)));
|
||||
sctp_addto_chunk(*errp,
|
||||
sctp_addto_chunk_fixed(*errp,
|
||||
WORD_ROUND(ntohs(param.p->length)),
|
||||
param.v);
|
||||
} else {
|
||||
@@ -3315,21 +3370,6 @@ int sctp_process_asconf_ack(struct sctp_association *asoc,
|
||||
sctp_chunk_free(asconf);
|
||||
asoc->addip_last_asconf = NULL;
|
||||
|
||||
/* Send the next asconf chunk from the addip chunk queue. */
|
||||
if (!list_empty(&asoc->addip_chunk_list)) {
|
||||
struct list_head *entry = asoc->addip_chunk_list.next;
|
||||
asconf = list_entry(entry, struct sctp_chunk, list);
|
||||
|
||||
list_del_init(entry);
|
||||
|
||||
/* Hold the chunk until an ASCONF_ACK is received. */
|
||||
sctp_chunk_hold(asconf);
|
||||
if (sctp_primitive_ASCONF(asoc, asconf))
|
||||
sctp_chunk_free(asconf);
|
||||
else
|
||||
asoc->addip_last_asconf = asconf;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
@@ -962,6 +962,29 @@ static int sctp_cmd_send_msg(struct sctp_association *asoc,
|
||||
}
|
||||
|
||||
|
||||
/* Sent the next ASCONF packet currently stored in the association.
|
||||
* This happens after the ASCONF_ACK was succeffully processed.
|
||||
*/
|
||||
static void sctp_cmd_send_asconf(struct sctp_association *asoc)
|
||||
{
|
||||
/* Send the next asconf chunk from the addip chunk
|
||||
* queue.
|
||||
*/
|
||||
if (!list_empty(&asoc->addip_chunk_list)) {
|
||||
struct list_head *entry = asoc->addip_chunk_list.next;
|
||||
struct sctp_chunk *asconf = list_entry(entry,
|
||||
struct sctp_chunk, list);
|
||||
list_del_init(entry);
|
||||
|
||||
/* Hold the chunk until an ASCONF_ACK is received. */
|
||||
sctp_chunk_hold(asconf);
|
||||
if (sctp_primitive_ASCONF(asoc, asconf))
|
||||
sctp_chunk_free(asconf);
|
||||
else
|
||||
asoc->addip_last_asconf = asconf;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* These three macros allow us to pull the debugging code out of the
|
||||
* main flow of sctp_do_sm() to keep attention focused on the real
|
||||
@@ -1617,6 +1640,9 @@ static int sctp_cmd_interpreter(sctp_event_t event_type,
|
||||
}
|
||||
error = sctp_cmd_send_msg(asoc, cmd->obj.msg);
|
||||
break;
|
||||
case SCTP_CMD_SEND_NEXT_ASCONF:
|
||||
sctp_cmd_send_asconf(asoc);
|
||||
break;
|
||||
default:
|
||||
printk(KERN_WARNING "Impossible command: %u, %p\n",
|
||||
cmd->verb, cmd->obj.ptr);
|
||||
|
@@ -3676,8 +3676,14 @@ sctp_disposition_t sctp_sf_do_asconf_ack(const struct sctp_endpoint *ep,
|
||||
SCTP_TO(SCTP_EVENT_TIMEOUT_T4_RTO));
|
||||
|
||||
if (!sctp_process_asconf_ack((struct sctp_association *)asoc,
|
||||
asconf_ack))
|
||||
asconf_ack)) {
|
||||
/* Successfully processed ASCONF_ACK. We can
|
||||
* release the next asconf if we have one.
|
||||
*/
|
||||
sctp_add_cmd_sf(commands, SCTP_CMD_SEND_NEXT_ASCONF,
|
||||
SCTP_NULL());
|
||||
return SCTP_DISPOSITION_CONSUME;
|
||||
}
|
||||
|
||||
abort = sctp_make_abort(asoc, asconf_ack,
|
||||
sizeof(sctp_errhdr_t));
|
||||
|
@@ -3719,9 +3719,9 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk)
|
||||
sp->hmac = NULL;
|
||||
|
||||
SCTP_DBG_OBJCNT_INC(sock);
|
||||
percpu_counter_inc(&sctp_sockets_allocated);
|
||||
|
||||
local_bh_disable();
|
||||
percpu_counter_inc(&sctp_sockets_allocated);
|
||||
sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
|
||||
local_bh_enable();
|
||||
|
||||
@@ -3738,8 +3738,8 @@ SCTP_STATIC void sctp_destroy_sock(struct sock *sk)
|
||||
/* Release our hold on the endpoint. */
|
||||
ep = sctp_sk(sk)->ep;
|
||||
sctp_endpoint_free(ep);
|
||||
percpu_counter_dec(&sctp_sockets_allocated);
|
||||
local_bh_disable();
|
||||
percpu_counter_dec(&sctp_sockets_allocated);
|
||||
sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1);
|
||||
local_bh_enable();
|
||||
}
|
||||
@@ -6185,6 +6185,19 @@ do_nonblock:
|
||||
goto out;
|
||||
}
|
||||
|
||||
void sctp_data_ready(struct sock *sk, int len)
|
||||
{
|
||||
struct socket_wq *wq;
|
||||
|
||||
rcu_read_lock();
|
||||
wq = rcu_dereference(sk->sk_wq);
|
||||
if (wq_has_sleeper(wq))
|
||||
wake_up_interruptible_sync_poll(&wq->wait, POLLIN |
|
||||
POLLRDNORM | POLLRDBAND);
|
||||
sk_wake_async(sk, SOCK_WAKE_WAITD, POLL_IN);
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
/* If socket sndbuf has changed, wake up all per association waiters. */
|
||||
void sctp_write_space(struct sock *sk)
|
||||
{
|
||||
|
Reference in New Issue
Block a user