Commit df218577 authored by Vlad Yasevich's avatar Vlad Yasevich Committed by David S. Miller

[SCTP]: Update association lookup to look at ASCONF chunks as well

ADD-IP draft section 5.2 specifies that if an association can not
be found using the source and destination of the IP packet,
then, if the packet contains ASCONF chunks, the Address Parameter
TLV should be used to lookup an association.
Signed-off-by: default avatarVlad Yasevich <vladislav.yasevich@hp.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent d6de3097
...@@ -891,14 +891,6 @@ static struct sctp_association *__sctp_rcv_init_lookup(struct sk_buff *skb, ...@@ -891,14 +891,6 @@ static struct sctp_association *__sctp_rcv_init_lookup(struct sk_buff *skb,
ch = (sctp_chunkhdr_t *) skb->data; ch = (sctp_chunkhdr_t *) skb->data;
/* 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
* walk off the end.
*/
if (WORD_ROUND(ntohs(ch->length)) > skb->len)
return NULL;
/* /*
* This code will NOT touch anything inside the chunk--it is * This code will NOT touch anything inside the chunk--it is
* strictly READ-ONLY. * strictly READ-ONLY.
...@@ -935,6 +927,44 @@ static struct sctp_association *__sctp_rcv_init_lookup(struct sk_buff *skb, ...@@ -935,6 +927,44 @@ static struct sctp_association *__sctp_rcv_init_lookup(struct sk_buff *skb,
return NULL; return NULL;
} }
/* ADD-IP, Section 5.2
* When an endpoint receives an ASCONF Chunk from the remote peer
* special procedures may be needed to identify the association the
* ASCONF Chunk is associated with. To properly find the association
* the following procedures SHOULD be followed:
*
* D2) If the association is not found, use the address found in the
* Address Parameter TLV combined with the port number found in the
* SCTP common header. If found proceed to rule D4.
*
* D2-ext) If more than one ASCONF Chunks are packed together, use the
* address found in the ASCONF Address Parameter TLV of each of the
* subsequent ASCONF Chunks. If found, proceed to rule D4.
*/
static struct sctp_association *__sctp_rcv_asconf_lookup(
sctp_chunkhdr_t *ch,
const union sctp_addr *laddr,
__be32 peer_port,
struct sctp_transport **transportp)
{
sctp_addip_chunk_t *asconf = (struct sctp_addip_chunk *)ch;
struct sctp_af *af;
union sctp_addr_param *param;
union sctp_addr paddr;
/* Skip over the ADDIP header and find the Address parameter */
param = (union sctp_addr_param *)(asconf + 1);
af = sctp_get_af_specific(param_type2af(param->v4.param_hdr.type));
if (unlikely(!af))
return NULL;
af->from_addr_param(&paddr, param, peer_port, 0);
return __sctp_lookup_association(laddr, &paddr, transportp);
}
/* SCTP-AUTH, Section 6.3: /* SCTP-AUTH, Section 6.3:
* If the receiver does not find a STCB for a packet containing an AUTH * 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 as the first chunk and not a COOKIE-ECHO chunk as the second
...@@ -943,20 +973,64 @@ static struct sctp_association *__sctp_rcv_init_lookup(struct sk_buff *skb, ...@@ -943,20 +973,64 @@ static struct sctp_association *__sctp_rcv_init_lookup(struct sk_buff *skb,
* *
* This means that any chunks that can help us identify the association need * This means that any chunks that can help us identify the association need
* to be looked at to find this assocation. * 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, static struct sctp_association *__sctp_rcv_walk_lookup(struct sk_buff *skb,
const union sctp_addr *paddr,
const union sctp_addr *laddr, const union sctp_addr *laddr,
struct sctp_transport **transportp) struct sctp_transport **transportp)
{ {
/* XXX - walk through the chunks looking for something that can struct sctp_association *asoc = NULL;
* help us find the association. INIT, and INIT-ACK are not permitted. sctp_chunkhdr_t *ch;
* That leaves ASCONF, but we don't support that yet. int have_auth = 0;
unsigned int chunk_num = 1;
__u8 *ch_end;
/* Walk through the chunks looking for AUTH or ASCONF chunks
* to help us find the association.
*/ */
ch = (sctp_chunkhdr_t *) skb->data;
do {
/* Break out if chunk length is less then minimal. */
if (ntohs(ch->length) < sizeof(sctp_chunkhdr_t))
break;
ch_end = ((__u8 *)ch) + WORD_ROUND(ntohs(ch->length));
if (ch_end > skb_tail_pointer(skb))
break;
switch(ch->type) {
case SCTP_CID_AUTH:
have_auth = chunk_num;
break;
case SCTP_CID_COOKIE_ECHO:
/* If a packet arrives containing an AUTH chunk as
* a first chunk, a COOKIE-ECHO chunk as the second
* chunk, and possibly more chunks after them, and
* the receiver does not have an STCB for that
* packet, then authentication is based on
* the contents of the COOKIE- ECHO chunk.
*/
if (have_auth == 1 && chunk_num == 2)
return NULL; return NULL;
break;
case SCTP_CID_ASCONF:
if (have_auth || sctp_addip_noauth)
asoc = __sctp_rcv_asconf_lookup(ch, laddr,
sctp_hdr(skb)->source,
transportp);
default:
break;
}
if (asoc)
break;
ch = (sctp_chunkhdr_t *) ch_end;
chunk_num++;
} while (ch_end < skb_tail_pointer(skb));
return asoc;
} }
/* /*
...@@ -966,7 +1040,6 @@ static struct sctp_association *__sctp_rcv_auth_lookup(struct sk_buff *skb, ...@@ -966,7 +1040,6 @@ static struct sctp_association *__sctp_rcv_auth_lookup(struct sk_buff *skb,
* chunks. * chunks.
*/ */
static struct sctp_association *__sctp_rcv_lookup_harder(struct sk_buff *skb, static struct sctp_association *__sctp_rcv_lookup_harder(struct sk_buff *skb,
const union sctp_addr *paddr,
const union sctp_addr *laddr, const union sctp_addr *laddr,
struct sctp_transport **transportp) struct sctp_transport **transportp)
{ {
...@@ -974,6 +1047,14 @@ static struct sctp_association *__sctp_rcv_lookup_harder(struct sk_buff *skb, ...@@ -974,6 +1047,14 @@ static struct sctp_association *__sctp_rcv_lookup_harder(struct sk_buff *skb,
ch = (sctp_chunkhdr_t *) skb->data; ch = (sctp_chunkhdr_t *) skb->data;
/* 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
* walk off the end.
*/
if (WORD_ROUND(ntohs(ch->length)) > skb->len)
return NULL;
/* If this is INIT/INIT-ACK look inside the chunk too. */ /* If this is INIT/INIT-ACK look inside the chunk too. */
switch (ch->type) { switch (ch->type) {
case SCTP_CID_INIT: case SCTP_CID_INIT:
...@@ -981,11 +1062,12 @@ static struct sctp_association *__sctp_rcv_lookup_harder(struct sk_buff *skb, ...@@ -981,11 +1062,12 @@ static struct sctp_association *__sctp_rcv_lookup_harder(struct sk_buff *skb,
return __sctp_rcv_init_lookup(skb, laddr, transportp); return __sctp_rcv_init_lookup(skb, laddr, transportp);
break; break;
case SCTP_CID_AUTH: default:
return __sctp_rcv_auth_lookup(skb, paddr, laddr, transportp); return __sctp_rcv_walk_lookup(skb, laddr, transportp);
break; break;
} }
return NULL; return NULL;
} }
...@@ -1004,7 +1086,7 @@ static struct sctp_association *__sctp_rcv_lookup(struct sk_buff *skb, ...@@ -1004,7 +1086,7 @@ static struct sctp_association *__sctp_rcv_lookup(struct sk_buff *skb,
* parameters within the INIT or INIT-ACK. * parameters within the INIT or INIT-ACK.
*/ */
if (!asoc) if (!asoc)
asoc = __sctp_rcv_lookup_harder(skb, paddr, laddr, transportp); asoc = __sctp_rcv_lookup_harder(skb, laddr, transportp);
return asoc; return asoc;
} }
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