Skip to content

Commit

Permalink
[SCTP]: Implement the receive and verification of AUTH chunk
Browse files Browse the repository at this point in the history
This patch implements the receive path needed to process authenticated
chunks.  Add ability to process the AUTH chunk and handle edge cases
for authenticated COOKIE-ECHO as well.

Signed-off-by: Vlad Yasevich <vladislav.yasevich@hp.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Vlad Yasevich authored and David S. Miller committed Oct 10, 2007
1 parent 4cd57c8 commit bbd0d59
Show file tree
Hide file tree
Showing 9 changed files with 374 additions and 13 deletions.
4 changes: 3 additions & 1 deletion include/net/sctp/constants.h
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,9 @@ typedef enum {
SCTP_IERROR_NO_DATA,
SCTP_IERROR_BAD_STREAM,
SCTP_IERROR_BAD_PORTS,

SCTP_IERROR_AUTH_BAD_HMAC,
SCTP_IERROR_AUTH_BAD_KEYID,
SCTP_IERROR_PROTO_VIOLATION,
} sctp_ierror_t;


Expand Down
1 change: 1 addition & 0 deletions include/net/sctp/sm.h
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ sctp_state_fn_t sctp_sf_do_asconf_ack;
sctp_state_fn_t sctp_sf_do_9_2_reshutack;
sctp_state_fn_t sctp_sf_eat_fwd_tsn;
sctp_state_fn_t sctp_sf_eat_fwd_tsn_fast;
sctp_state_fn_t sctp_sf_eat_auth;

/* Prototypes for primitive event state functions. */
sctp_state_fn_t sctp_sf_do_prm_asoc;
Expand Down
8 changes: 8 additions & 0 deletions include/net/sctp/structs.h
Original file line number Diff line number Diff line change
Expand Up @@ -724,6 +724,13 @@ struct sctp_chunk {
*/
struct sctp_transport *transport;

/* SCTP-AUTH: For the special case inbound processing of COOKIE-ECHO
* we need save a pointer to the AUTH chunk, since the SCTP-AUTH
* spec violates the principle premis that all chunks are processed
* in order.
*/
struct sk_buff *auth_chunk;

__u8 rtt_in_progress; /* Is this chunk used for RTT calculation? */
__u8 resent; /* Has this chunk ever been retransmitted. */
__u8 has_tsn; /* Does this chunk have a TSN yet? */
Expand Down Expand Up @@ -1067,6 +1074,7 @@ void sctp_inq_init(struct sctp_inq *);
void sctp_inq_free(struct sctp_inq *);
void sctp_inq_push(struct sctp_inq *, struct sctp_chunk *packet);
struct sctp_chunk *sctp_inq_pop(struct sctp_inq *);
struct sctp_chunkhdr *sctp_inq_peek(struct sctp_inq *);
void sctp_inq_set_th_handler(struct sctp_inq *, work_func_t);

/* This is the structure we use to hold outbound chunks. You push
Expand Down
10 changes: 10 additions & 0 deletions net/sctp/associola.c
Original file line number Diff line number Diff line change
Expand Up @@ -1011,6 +1011,16 @@ static void sctp_assoc_bh_rcv(struct work_struct *work)
state = asoc->state;
subtype = SCTP_ST_CHUNK(chunk->chunk_hdr->type);

/* SCTP-AUTH, Section 6.3:
* The receiver has a list of chunk types which it expects
* to be received only after an AUTH-chunk. This list has
* been sent to the peer during the association setup. It
* MUST silently discard these chunks if they are not placed
* after an AUTH chunk in the packet.
*/
if (sctp_auth_recv_cid(subtype.chunk, asoc) && !chunk->auth)
continue;

/* Remember where the last DATA chunk came from so we
* know where to send the SACK.
*/
Expand Down
29 changes: 29 additions & 0 deletions net/sctp/endpointola.c
Original file line number Diff line number Diff line change
Expand Up @@ -400,6 +400,7 @@ static void sctp_endpoint_bh_rcv(struct work_struct *work)
sctp_subtype_t subtype;
sctp_state_t state;
int error = 0;
int first_time = 1; /* is this the first time through the looop */

if (ep->base.dead)
return;
Expand All @@ -411,6 +412,29 @@ static void sctp_endpoint_bh_rcv(struct work_struct *work)
while (NULL != (chunk = sctp_inq_pop(inqueue))) {
subtype = SCTP_ST_CHUNK(chunk->chunk_hdr->type);

/* If the first chunk in the packet is AUTH, do special
* processing specified in Section 6.3 of SCTP-AUTH spec
*/
if (first_time && (subtype.chunk == SCTP_CID_AUTH)) {
struct sctp_chunkhdr *next_hdr;

next_hdr = sctp_inq_peek(inqueue);
if (!next_hdr)
goto normal;

/* If the next chunk is COOKIE-ECHO, skip the AUTH
* chunk while saving a pointer to it so we can do
* Authentication later (during cookie-echo
* processing).
*/
if (next_hdr->type == SCTP_CID_COOKIE_ECHO) {
chunk->auth_chunk = skb_clone(chunk->skb,
GFP_ATOMIC);
chunk->auth = 1;
continue;
}
}
normal:
/* We might have grown an association since last we
* looked, so try again.
*
Expand All @@ -426,6 +450,8 @@ static void sctp_endpoint_bh_rcv(struct work_struct *work)
}

state = asoc ? asoc->state : SCTP_STATE_CLOSED;
if (sctp_auth_recv_cid(subtype.chunk, asoc) && !chunk->auth)
continue;

/* Remember where the last DATA chunk came from so we
* know where to send the SACK.
Expand All @@ -449,5 +475,8 @@ static void sctp_endpoint_bh_rcv(struct work_struct *work)
*/
if (!sctp_sk(sk)->ep)
break;

if (first_time)
first_time = 0;
}
}
65 changes: 55 additions & 10 deletions net/sctp/input.c
Original file line number Diff line number Diff line change
Expand Up @@ -911,15 +911,6 @@ static struct sctp_association *__sctp_rcv_init_lookup(struct sk_buff *skb,

ch = (sctp_chunkhdr_t *) skb->data;

/* If this is INIT/INIT-ACK look inside the chunk too. */
switch (ch->type) {
case SCTP_CID_INIT:
case SCTP_CID_INIT_ACK:
break;
default:
return NULL;
}

/* The code below will attempt to walk the chunk and extract
* parameter information. Before we do that, we need to verify
* that the chunk length doesn't cause overflow. Otherwise, we'll
Expand Down Expand Up @@ -964,6 +955,60 @@ static struct sctp_association *__sctp_rcv_init_lookup(struct sk_buff *skb,
return NULL;
}

/* SCTP-AUTH, Section 6.3:
* If the receiver does not find a STCB for a packet containing an AUTH
* chunk as the first chunk and not a COOKIE-ECHO chunk as the second
* chunk, it MUST use the chunks after the AUTH chunk to look up an existing
* association.
*
* This means that any chunks that can help us identify the association need
* to be looked at to find this assocation.
*
* TODO: The only chunk currently defined that can do that is ASCONF, but we
* don't support that functionality yet.
*/
static struct sctp_association *__sctp_rcv_auth_lookup(struct sk_buff *skb,
const union sctp_addr *paddr,
const union sctp_addr *laddr,
struct sctp_transport **transportp)
{
/* XXX - walk through the chunks looking for something that can
* help us find the association. INIT, and INIT-ACK are not permitted.
* That leaves ASCONF, but we don't support that yet.
*/
return NULL;
}

/*
* There are circumstances when we need to look inside the SCTP packet
* for information to help us find the association. Examples
* include looking inside of INIT/INIT-ACK chunks or after the AUTH
* chunks.
*/
static struct sctp_association *__sctp_rcv_lookup_harder(struct sk_buff *skb,
const union sctp_addr *paddr,
const union sctp_addr *laddr,
struct sctp_transport **transportp)
{
sctp_chunkhdr_t *ch;

ch = (sctp_chunkhdr_t *) skb->data;

/* If this is INIT/INIT-ACK look inside the chunk too. */
switch (ch->type) {
case SCTP_CID_INIT:
case SCTP_CID_INIT_ACK:
return __sctp_rcv_init_lookup(skb, laddr, transportp);
break;

case SCTP_CID_AUTH:
return __sctp_rcv_auth_lookup(skb, paddr, laddr, transportp);
break;
}

return NULL;
}

/* Lookup an association for an inbound skb. */
static struct sctp_association *__sctp_rcv_lookup(struct sk_buff *skb,
const union sctp_addr *paddr,
Expand All @@ -979,7 +1024,7 @@ static struct sctp_association *__sctp_rcv_lookup(struct sk_buff *skb,
* parameters within the INIT or INIT-ACK.
*/
if (!asoc)
asoc = __sctp_rcv_init_lookup(skb, laddr, transportp);
asoc = __sctp_rcv_lookup_harder(skb, paddr, laddr, transportp);

return asoc;
}
19 changes: 19 additions & 0 deletions net/sctp/inqueue.c
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,25 @@ void sctp_inq_push(struct sctp_inq *q, struct sctp_chunk *chunk)
q->immediate.func(&q->immediate);
}

/* Peek at the next chunk on the inqeue. */
struct sctp_chunkhdr *sctp_inq_peek(struct sctp_inq *queue)
{
struct sctp_chunk *chunk;
sctp_chunkhdr_t *ch = NULL;

chunk = queue->in_progress;
/* If there is no more chunks in this packet, say so */
if (chunk->singleton ||
chunk->end_of_packet ||
chunk->pdiscard)
return NULL;

ch = (sctp_chunkhdr_t *)chunk->chunk_end;

return ch;
}


/* Extract a chunk from an SCTP inqueue.
*
* WARNING: If you need to put the chunk on another queue, you need to
Expand Down
Loading

0 comments on commit bbd0d59

Please sign in to comment.