mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-10-02 23:27:06 +00:00
net: sctp: Add rudimentary infrastructure to account for control chunks
This patch adds a base infrastructure that allows SCTP to do memory accounting for control chunks. Real accounting code will follow. This patch alos fixes the following triggered bug ... [ 553.109742] kernel BUG at include/linux/skbuff.h:1813! [ 553.109766] invalid opcode: 0000 [#1] SMP [ 553.109789] Modules linked in: sctp libcrc32c rfcomm [...] [ 553.110259] uinput i915 i2c_algo_bit drm_kms_helper e1000e drm ptp pps_core i2c_core wmi video sunrpc [ 553.110320] CPU: 0 PID: 1636 Comm: lt-test_1_to_1_ Not tainted 3.11.0-rc3+ #2 [ 553.110350] Hardware name: LENOVO 74597D6/74597D6, BIOS 6DET60WW (3.10 ) 09/17/2009 [ 553.110381] task: ffff88020a01dd40 ti: ffff880204ed0000 task.ti: ffff880204ed0000 [ 553.110411] RIP: 0010:[<ffffffffa0698017>] [<ffffffffa0698017>] skb_orphan.part.9+0x4/0x6 [sctp] [ 553.110459] RSP: 0018:ffff880204ed1bb8 EFLAGS: 00010286 [ 553.110483] RAX: ffff8802086f5a40 RBX: ffff880204303300 RCX: 0000000000000000 [ 553.110487] RDX: ffff880204303c28 RSI: ffff8802086f5a40 RDI: ffff880202158000 [ 553.110487] RBP: ffff880204ed1bb8 R08: 0000000000000000 R09: 0000000000000000 [ 553.110487] R10: ffff88022f2d9a04 R11: ffff880233001600 R12: 0000000000000000 [ 553.110487] R13: ffff880204303c00 R14: ffff8802293d0000 R15: ffff880202158000 [ 553.110487] FS: 00007f31b31fe740(0000) GS:ffff88023bc00000(0000) knlGS:0000000000000000 [ 553.110487] CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b [ 553.110487] CR2: 000000379980e3e0 CR3: 000000020d225000 CR4: 00000000000407f0 [ 553.110487] Stack: [ 553.110487] ffff880204ed1ca8 ffffffffa068d7fc 0000000000000000 0000000000000000 [ 553.110487] 0000000000000000 ffff8802293d0000 ffff880202158000 ffffffff81cb7900 [ 553.110487] 0000000000000000 0000400000001c68 ffff8802086f5a40 000000000000000f [ 553.110487] Call Trace: [ 553.110487] [<ffffffffa068d7fc>] sctp_sendmsg+0x6bc/0xc80 [sctp] [ 553.110487] [<ffffffff8128f185>] ? sock_has_perm+0x75/0x90 [ 553.110487] [<ffffffff815a3593>] inet_sendmsg+0x63/0xb0 [ 553.110487] [<ffffffff8128f2b3>] ? selinux_socket_sendmsg+0x23/0x30 [ 553.110487] [<ffffffff8151c5d6>] sock_sendmsg+0xa6/0xd0 [ 553.110487] [<ffffffff81637b05>] ? _raw_spin_unlock_bh+0x15/0x20 [ 553.110487] [<ffffffff8151cd38>] SYSC_sendto+0x128/0x180 [ 553.110487] [<ffffffff8151ce6b>] ? SYSC_connect+0xdb/0x100 [ 553.110487] [<ffffffffa0690031>] ? sctp_inet_listen+0x71/0x1f0 [sctp] [ 553.110487] [<ffffffff8151d35e>] SyS_sendto+0xe/0x10 [ 553.110487] [<ffffffff81640202>] system_call_fastpath+0x16/0x1b [ 553.110487] Code: e0 48 c7 c7 00 22 6a a0 e8 67 a3 f0 e0 48 c7 [...] [ 553.110487] RIP [<ffffffffa0698017>] skb_orphan.part.9+0x4/0x6 [sctp] [ 553.110487] RSP <ffff880204ed1bb8> [ 553.121578] ---[ end trace 46c20c5903ef5be2 ]--- The approach taken here is to split data and control chunks creation a bit. Data chunks already have memory accounting so noting needs to happen. For control chunks, add stubs handlers. Signed-off-by: Vlad Yasevich <vyasevich@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
55d10a11ae
commit
072017b41e
1 changed files with 69 additions and 30 deletions
|
@ -62,7 +62,11 @@
|
||||||
#include <net/sctp/sctp.h>
|
#include <net/sctp/sctp.h>
|
||||||
#include <net/sctp/sm.h>
|
#include <net/sctp/sm.h>
|
||||||
|
|
||||||
static struct sctp_chunk *sctp_make_chunk(const struct sctp_association *asoc,
|
static struct sctp_chunk *sctp_make_control(const struct sctp_association *asoc,
|
||||||
|
__u8 type, __u8 flags, int paylen);
|
||||||
|
static struct sctp_chunk *sctp_make_data(const struct sctp_association *asoc,
|
||||||
|
__u8 flags, int paylen);
|
||||||
|
static struct sctp_chunk *_sctp_make_chunk(const struct sctp_association *asoc,
|
||||||
__u8 type, __u8 flags, int paylen);
|
__u8 type, __u8 flags, int paylen);
|
||||||
static sctp_cookie_param_t *sctp_pack_cookie(const struct sctp_endpoint *ep,
|
static sctp_cookie_param_t *sctp_pack_cookie(const struct sctp_endpoint *ep,
|
||||||
const struct sctp_association *asoc,
|
const struct sctp_association *asoc,
|
||||||
|
@ -76,6 +80,28 @@ static int sctp_process_param(struct sctp_association *asoc,
|
||||||
static void *sctp_addto_param(struct sctp_chunk *chunk, int len,
|
static void *sctp_addto_param(struct sctp_chunk *chunk, int len,
|
||||||
const void *data);
|
const void *data);
|
||||||
|
|
||||||
|
/* Control chunk destructor */
|
||||||
|
static void sctp_control_release_owner(struct sk_buff *skb)
|
||||||
|
{
|
||||||
|
/*TODO: do memory release */
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sctp_control_set_owner_w(struct sctp_chunk *chunk)
|
||||||
|
{
|
||||||
|
struct sctp_association *asoc = chunk->asoc;
|
||||||
|
struct sk_buff *skb = chunk->skb;
|
||||||
|
|
||||||
|
/* TODO: properly account for control chunks.
|
||||||
|
* To do it right we'll need:
|
||||||
|
* 1) endpoint if association isn't known.
|
||||||
|
* 2) proper memory accounting.
|
||||||
|
*
|
||||||
|
* For now don't do anything for now.
|
||||||
|
*/
|
||||||
|
skb->sk = asoc ? asoc->base.sk : NULL;
|
||||||
|
skb->destructor = sctp_control_release_owner;
|
||||||
|
}
|
||||||
|
|
||||||
/* What was the inbound interface for this chunk? */
|
/* What was the inbound interface for this chunk? */
|
||||||
int sctp_chunk_iif(const struct sctp_chunk *chunk)
|
int sctp_chunk_iif(const struct sctp_chunk *chunk)
|
||||||
{
|
{
|
||||||
|
@ -290,7 +316,7 @@ struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc,
|
||||||
* PLEASE DO NOT FIXME [This version does not support Host Name.]
|
* PLEASE DO NOT FIXME [This version does not support Host Name.]
|
||||||
*/
|
*/
|
||||||
|
|
||||||
retval = sctp_make_chunk(asoc, SCTP_CID_INIT, 0, chunksize);
|
retval = sctp_make_control(asoc, SCTP_CID_INIT, 0, chunksize);
|
||||||
if (!retval)
|
if (!retval)
|
||||||
goto nodata;
|
goto nodata;
|
||||||
|
|
||||||
|
@ -437,7 +463,7 @@ struct sctp_chunk *sctp_make_init_ack(const struct sctp_association *asoc,
|
||||||
num_ext);
|
num_ext);
|
||||||
|
|
||||||
/* Now allocate and fill out the chunk. */
|
/* Now allocate and fill out the chunk. */
|
||||||
retval = sctp_make_chunk(asoc, SCTP_CID_INIT_ACK, 0, chunksize);
|
retval = sctp_make_control(asoc, SCTP_CID_INIT_ACK, 0, chunksize);
|
||||||
if (!retval)
|
if (!retval)
|
||||||
goto nomem_chunk;
|
goto nomem_chunk;
|
||||||
|
|
||||||
|
@ -542,7 +568,7 @@ struct sctp_chunk *sctp_make_cookie_echo(const struct sctp_association *asoc,
|
||||||
cookie_len = asoc->peer.cookie_len;
|
cookie_len = asoc->peer.cookie_len;
|
||||||
|
|
||||||
/* Build a cookie echo chunk. */
|
/* Build a cookie echo chunk. */
|
||||||
retval = sctp_make_chunk(asoc, SCTP_CID_COOKIE_ECHO, 0, cookie_len);
|
retval = sctp_make_control(asoc, SCTP_CID_COOKIE_ECHO, 0, cookie_len);
|
||||||
if (!retval)
|
if (!retval)
|
||||||
goto nodata;
|
goto nodata;
|
||||||
retval->subh.cookie_hdr =
|
retval->subh.cookie_hdr =
|
||||||
|
@ -587,7 +613,7 @@ struct sctp_chunk *sctp_make_cookie_ack(const struct sctp_association *asoc,
|
||||||
{
|
{
|
||||||
struct sctp_chunk *retval;
|
struct sctp_chunk *retval;
|
||||||
|
|
||||||
retval = sctp_make_chunk(asoc, SCTP_CID_COOKIE_ACK, 0, 0);
|
retval = sctp_make_control(asoc, SCTP_CID_COOKIE_ACK, 0, 0);
|
||||||
|
|
||||||
/* RFC 2960 6.4 Multi-homed SCTP Endpoints
|
/* RFC 2960 6.4 Multi-homed SCTP Endpoints
|
||||||
*
|
*
|
||||||
|
@ -635,7 +661,7 @@ struct sctp_chunk *sctp_make_cwr(const struct sctp_association *asoc,
|
||||||
sctp_cwrhdr_t cwr;
|
sctp_cwrhdr_t cwr;
|
||||||
|
|
||||||
cwr.lowest_tsn = htonl(lowest_tsn);
|
cwr.lowest_tsn = htonl(lowest_tsn);
|
||||||
retval = sctp_make_chunk(asoc, SCTP_CID_ECN_CWR, 0,
|
retval = sctp_make_control(asoc, SCTP_CID_ECN_CWR, 0,
|
||||||
sizeof(sctp_cwrhdr_t));
|
sizeof(sctp_cwrhdr_t));
|
||||||
|
|
||||||
if (!retval)
|
if (!retval)
|
||||||
|
@ -669,7 +695,7 @@ struct sctp_chunk *sctp_make_ecne(const struct sctp_association *asoc,
|
||||||
sctp_ecnehdr_t ecne;
|
sctp_ecnehdr_t ecne;
|
||||||
|
|
||||||
ecne.lowest_tsn = htonl(lowest_tsn);
|
ecne.lowest_tsn = htonl(lowest_tsn);
|
||||||
retval = sctp_make_chunk(asoc, SCTP_CID_ECN_ECNE, 0,
|
retval = sctp_make_control(asoc, SCTP_CID_ECN_ECNE, 0,
|
||||||
sizeof(sctp_ecnehdr_t));
|
sizeof(sctp_ecnehdr_t));
|
||||||
if (!retval)
|
if (!retval)
|
||||||
goto nodata;
|
goto nodata;
|
||||||
|
@ -706,7 +732,7 @@ struct sctp_chunk *sctp_make_datafrag_empty(struct sctp_association *asoc,
|
||||||
dp.ssn = htons(ssn);
|
dp.ssn = htons(ssn);
|
||||||
|
|
||||||
chunk_len = sizeof(dp) + data_len;
|
chunk_len = sizeof(dp) + data_len;
|
||||||
retval = sctp_make_chunk(asoc, SCTP_CID_DATA, flags, chunk_len);
|
retval = sctp_make_data(asoc, flags, chunk_len);
|
||||||
if (!retval)
|
if (!retval)
|
||||||
goto nodata;
|
goto nodata;
|
||||||
|
|
||||||
|
@ -753,7 +779,7 @@ struct sctp_chunk *sctp_make_sack(const struct sctp_association *asoc)
|
||||||
+ sizeof(__u32) * num_dup_tsns;
|
+ sizeof(__u32) * num_dup_tsns;
|
||||||
|
|
||||||
/* Create the chunk. */
|
/* Create the chunk. */
|
||||||
retval = sctp_make_chunk(asoc, SCTP_CID_SACK, 0, len);
|
retval = sctp_make_control(asoc, SCTP_CID_SACK, 0, len);
|
||||||
if (!retval)
|
if (!retval)
|
||||||
goto nodata;
|
goto nodata;
|
||||||
|
|
||||||
|
@ -832,7 +858,7 @@ struct sctp_chunk *sctp_make_shutdown(const struct sctp_association *asoc,
|
||||||
ctsn = sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map);
|
ctsn = sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map);
|
||||||
shut.cum_tsn_ack = htonl(ctsn);
|
shut.cum_tsn_ack = htonl(ctsn);
|
||||||
|
|
||||||
retval = sctp_make_chunk(asoc, SCTP_CID_SHUTDOWN, 0,
|
retval = sctp_make_control(asoc, SCTP_CID_SHUTDOWN, 0,
|
||||||
sizeof(sctp_shutdownhdr_t));
|
sizeof(sctp_shutdownhdr_t));
|
||||||
if (!retval)
|
if (!retval)
|
||||||
goto nodata;
|
goto nodata;
|
||||||
|
@ -851,7 +877,7 @@ struct sctp_chunk *sctp_make_shutdown_ack(const struct sctp_association *asoc,
|
||||||
{
|
{
|
||||||
struct sctp_chunk *retval;
|
struct sctp_chunk *retval;
|
||||||
|
|
||||||
retval = sctp_make_chunk(asoc, SCTP_CID_SHUTDOWN_ACK, 0, 0);
|
retval = sctp_make_control(asoc, SCTP_CID_SHUTDOWN_ACK, 0, 0);
|
||||||
|
|
||||||
/* RFC 2960 6.4 Multi-homed SCTP Endpoints
|
/* RFC 2960 6.4 Multi-homed SCTP Endpoints
|
||||||
*
|
*
|
||||||
|
@ -880,7 +906,7 @@ struct sctp_chunk *sctp_make_shutdown_complete(
|
||||||
*/
|
*/
|
||||||
flags |= asoc ? 0 : SCTP_CHUNK_FLAG_T;
|
flags |= asoc ? 0 : SCTP_CHUNK_FLAG_T;
|
||||||
|
|
||||||
retval = sctp_make_chunk(asoc, SCTP_CID_SHUTDOWN_COMPLETE, flags, 0);
|
retval = sctp_make_control(asoc, SCTP_CID_SHUTDOWN_COMPLETE, flags, 0);
|
||||||
|
|
||||||
/* RFC 2960 6.4 Multi-homed SCTP Endpoints
|
/* RFC 2960 6.4 Multi-homed SCTP Endpoints
|
||||||
*
|
*
|
||||||
|
@ -919,7 +945,7 @@ struct sctp_chunk *sctp_make_abort(const struct sctp_association *asoc,
|
||||||
flags = SCTP_CHUNK_FLAG_T;
|
flags = SCTP_CHUNK_FLAG_T;
|
||||||
}
|
}
|
||||||
|
|
||||||
retval = sctp_make_chunk(asoc, SCTP_CID_ABORT, flags, hint);
|
retval = sctp_make_control(asoc, SCTP_CID_ABORT, flags, hint);
|
||||||
|
|
||||||
/* RFC 2960 6.4 Multi-homed SCTP Endpoints
|
/* RFC 2960 6.4 Multi-homed SCTP Endpoints
|
||||||
*
|
*
|
||||||
|
@ -1111,7 +1137,7 @@ struct sctp_chunk *sctp_make_heartbeat(const struct sctp_association *asoc,
|
||||||
struct sctp_chunk *retval;
|
struct sctp_chunk *retval;
|
||||||
sctp_sender_hb_info_t hbinfo;
|
sctp_sender_hb_info_t hbinfo;
|
||||||
|
|
||||||
retval = sctp_make_chunk(asoc, SCTP_CID_HEARTBEAT, 0, sizeof(hbinfo));
|
retval = sctp_make_control(asoc, SCTP_CID_HEARTBEAT, 0, sizeof(hbinfo));
|
||||||
|
|
||||||
if (!retval)
|
if (!retval)
|
||||||
goto nodata;
|
goto nodata;
|
||||||
|
@ -1139,7 +1165,7 @@ struct sctp_chunk *sctp_make_heartbeat_ack(const struct sctp_association *asoc,
|
||||||
{
|
{
|
||||||
struct sctp_chunk *retval;
|
struct sctp_chunk *retval;
|
||||||
|
|
||||||
retval = sctp_make_chunk(asoc, SCTP_CID_HEARTBEAT_ACK, 0, paylen);
|
retval = sctp_make_control(asoc, SCTP_CID_HEARTBEAT_ACK, 0, paylen);
|
||||||
if (!retval)
|
if (!retval)
|
||||||
goto nodata;
|
goto nodata;
|
||||||
|
|
||||||
|
@ -1171,7 +1197,7 @@ static struct sctp_chunk *sctp_make_op_error_space(
|
||||||
{
|
{
|
||||||
struct sctp_chunk *retval;
|
struct sctp_chunk *retval;
|
||||||
|
|
||||||
retval = sctp_make_chunk(asoc, SCTP_CID_ERROR, 0,
|
retval = sctp_make_control(asoc, SCTP_CID_ERROR, 0,
|
||||||
sizeof(sctp_errhdr_t) + size);
|
sizeof(sctp_errhdr_t) + size);
|
||||||
if (!retval)
|
if (!retval)
|
||||||
goto nodata;
|
goto nodata;
|
||||||
|
@ -1242,7 +1268,7 @@ struct sctp_chunk *sctp_make_auth(const struct sctp_association *asoc)
|
||||||
if (unlikely(!hmac_desc))
|
if (unlikely(!hmac_desc))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
retval = sctp_make_chunk(asoc, SCTP_CID_AUTH, 0,
|
retval = sctp_make_control(asoc, SCTP_CID_AUTH, 0,
|
||||||
hmac_desc->hmac_len + sizeof(sctp_authhdr_t));
|
hmac_desc->hmac_len + sizeof(sctp_authhdr_t));
|
||||||
if (!retval)
|
if (!retval)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -1345,7 +1371,7 @@ const union sctp_addr *sctp_source(const struct sctp_chunk *chunk)
|
||||||
/* Create a new chunk, setting the type and flags headers from the
|
/* Create a new chunk, setting the type and flags headers from the
|
||||||
* arguments, reserving enough space for a 'paylen' byte payload.
|
* arguments, reserving enough space for a 'paylen' byte payload.
|
||||||
*/
|
*/
|
||||||
static struct sctp_chunk *sctp_make_chunk(const struct sctp_association *asoc,
|
static struct sctp_chunk *_sctp_make_chunk(const struct sctp_association *asoc,
|
||||||
__u8 type, __u8 flags, int paylen)
|
__u8 type, __u8 flags, int paylen)
|
||||||
{
|
{
|
||||||
struct sctp_chunk *retval;
|
struct sctp_chunk *retval;
|
||||||
|
@ -1379,14 +1405,27 @@ static struct sctp_chunk *sctp_make_chunk(const struct sctp_association *asoc,
|
||||||
if (sctp_auth_send_cid(type, asoc))
|
if (sctp_auth_send_cid(type, asoc))
|
||||||
retval->auth = 1;
|
retval->auth = 1;
|
||||||
|
|
||||||
/* Set the skb to the belonging sock for accounting. */
|
|
||||||
skb->sk = sk;
|
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
nodata:
|
nodata:
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct sctp_chunk *sctp_make_data(const struct sctp_association *asoc,
|
||||||
|
__u8 flags, int paylen)
|
||||||
|
{
|
||||||
|
return _sctp_make_chunk(asoc, SCTP_CID_DATA, flags, paylen);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct sctp_chunk *sctp_make_control(const struct sctp_association *asoc,
|
||||||
|
__u8 type, __u8 flags, int paylen)
|
||||||
|
{
|
||||||
|
struct sctp_chunk *chunk = _sctp_make_chunk(asoc, type, flags, paylen);
|
||||||
|
|
||||||
|
if (chunk)
|
||||||
|
sctp_control_set_owner_w(chunk);
|
||||||
|
|
||||||
|
return chunk;
|
||||||
|
}
|
||||||
|
|
||||||
/* Release the memory occupied by a chunk. */
|
/* Release the memory occupied by a chunk. */
|
||||||
static void sctp_chunk_destroy(struct sctp_chunk *chunk)
|
static void sctp_chunk_destroy(struct sctp_chunk *chunk)
|
||||||
|
@ -2727,7 +2766,7 @@ static struct sctp_chunk *sctp_make_asconf(struct sctp_association *asoc,
|
||||||
length += addrlen;
|
length += addrlen;
|
||||||
|
|
||||||
/* Create the chunk. */
|
/* Create the chunk. */
|
||||||
retval = sctp_make_chunk(asoc, SCTP_CID_ASCONF, 0, length);
|
retval = sctp_make_control(asoc, SCTP_CID_ASCONF, 0, length);
|
||||||
if (!retval)
|
if (!retval)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
@ -2911,7 +2950,7 @@ static struct sctp_chunk *sctp_make_asconf_ack(const struct sctp_association *as
|
||||||
int length = sizeof(asconf) + vparam_len;
|
int length = sizeof(asconf) + vparam_len;
|
||||||
|
|
||||||
/* Create the chunk. */
|
/* Create the chunk. */
|
||||||
retval = sctp_make_chunk(asoc, SCTP_CID_ASCONF_ACK, 0, length);
|
retval = sctp_make_control(asoc, SCTP_CID_ASCONF_ACK, 0, length);
|
||||||
if (!retval)
|
if (!retval)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
@ -3442,7 +3481,7 @@ struct sctp_chunk *sctp_make_fwdtsn(const struct sctp_association *asoc,
|
||||||
|
|
||||||
hint = (nstreams + 1) * sizeof(__u32);
|
hint = (nstreams + 1) * sizeof(__u32);
|
||||||
|
|
||||||
retval = sctp_make_chunk(asoc, SCTP_CID_FWD_TSN, 0, hint);
|
retval = sctp_make_control(asoc, SCTP_CID_FWD_TSN, 0, hint);
|
||||||
|
|
||||||
if (!retval)
|
if (!retval)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
Loading…
Reference in a new issue