aboutsummaryrefslogtreecommitdiff
path: root/net/sctp/output.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@woody.linux-foundation.org>2007-10-11 19:40:14 -0700
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-10-11 19:40:14 -0700
commit038a5008b2f395c85e6e71d6ddf3c684e7c405b0 (patch)
tree4735eab577e97e5a22c3141e3f60071c8065585e /net/sctp/output.c
parentdd6d1844af33acb4edd0a40b1770d091a22c94be (diff)
parent266918303226cceac7eca38ced30f15f277bd89c (diff)
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6
* 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6: (867 commits) [SKY2]: status polling loop (post merge) [NET]: Fix NAPI completion handling in some drivers. [TCP]: Limit processing lost_retrans loop to work-to-do cases [TCP]: Fix lost_retrans loop vs fastpath problems [TCP]: No need to re-count fackets_out/sacked_out at RTO [TCP]: Extract tcp_match_queue_to_sack from sacktag code [TCP]: Kill almost unused variable pcount from sacktag [TCP]: Fix mark_head_lost to ignore R-bit when trying to mark L [TCP]: Add bytes_acked (ABC) clearing to FRTO too [IPv6]: Update setsockopt(IPV6_MULTICAST_IF) to support RFC 3493, try2 [NETFILTER]: x_tables: add missing ip6t_modulename aliases [NETFILTER]: nf_conntrack_tcp: fix connection reopening [QETH]: fix qeth_main.c [NETLINK]: fib_frontend build fixes [IPv6]: Export userland ND options through netlink (RDNSS support) [9P]: build fix with !CONFIG_SYSCTL [NET]: Fix dev_put() and dev_hold() comments [NET]: make netlink user -> kernel interface synchronious [NET]: unify netlink kernel socket recognition [NET]: cleanup 3rd argument in netlink_sendskb ... Fix up conflicts manually in Documentation/feature-removal-schedule.txt and my new least favourite crap, the "mod_devicetable" support in the files include/linux/mod_devicetable.h and scripts/mod/file2alias.c. (The latter files seem to be explicitly _designed_ to get conflicts when different subsystems work with them - that have an absolutely horrid lack of subsystem separation!) Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'net/sctp/output.c')
-rw-r--r--net/sctp/output.c135
1 files changed, 108 insertions, 27 deletions
diff --git a/net/sctp/output.c b/net/sctp/output.c
index d85543def75..847639d542c 100644
--- a/net/sctp/output.c
+++ b/net/sctp/output.c
@@ -79,7 +79,10 @@ struct sctp_packet *sctp_packet_config(struct sctp_packet *packet,
packet->vtag = vtag;
packet->has_cookie_echo = 0;
packet->has_sack = 0;
+ packet->has_auth = 0;
+ packet->has_data = 0;
packet->ipfragok = 0;
+ packet->auth = NULL;
if (ecn_capable && sctp_packet_empty(packet)) {
chunk = sctp_get_ecne_prepend(packet->transport->asoc);
@@ -121,8 +124,11 @@ struct sctp_packet *sctp_packet_init(struct sctp_packet *packet,
packet->vtag = 0;
packet->has_cookie_echo = 0;
packet->has_sack = 0;
+ packet->has_auth = 0;
+ packet->has_data = 0;
packet->ipfragok = 0;
packet->malloced = 0;
+ packet->auth = NULL;
return packet;
}
@@ -181,6 +187,39 @@ sctp_xmit_t sctp_packet_transmit_chunk(struct sctp_packet *packet,
return retval;
}
+/* Try to bundle an auth chunk into the packet. */
+static sctp_xmit_t sctp_packet_bundle_auth(struct sctp_packet *pkt,
+ struct sctp_chunk *chunk)
+{
+ struct sctp_association *asoc = pkt->transport->asoc;
+ struct sctp_chunk *auth;
+ sctp_xmit_t retval = SCTP_XMIT_OK;
+
+ /* if we don't have an association, we can't do authentication */
+ if (!asoc)
+ return retval;
+
+ /* See if this is an auth chunk we are bundling or if
+ * auth is already bundled.
+ */
+ if (chunk->chunk_hdr->type == SCTP_CID_AUTH || pkt->auth)
+ return retval;
+
+ /* if the peer did not request this chunk to be authenticated,
+ * don't do it
+ */
+ if (!chunk->auth)
+ return retval;
+
+ auth = sctp_make_auth(asoc);
+ if (!auth)
+ return retval;
+
+ retval = sctp_packet_append_chunk(pkt, auth);
+
+ return retval;
+}
+
/* Try to bundle a SACK with the packet. */
static sctp_xmit_t sctp_packet_bundle_sack(struct sctp_packet *pkt,
struct sctp_chunk *chunk)
@@ -227,12 +266,17 @@ sctp_xmit_t sctp_packet_append_chunk(struct sctp_packet *packet,
SCTP_DEBUG_PRINTK("%s: packet:%p chunk:%p\n", __FUNCTION__, packet,
chunk);
- retval = sctp_packet_bundle_sack(packet, chunk);
- psize = packet->size;
+ /* Try to bundle AUTH chunk */
+ retval = sctp_packet_bundle_auth(packet, chunk);
+ if (retval != SCTP_XMIT_OK)
+ goto finish;
+ /* Try to bundle SACK chunk */
+ retval = sctp_packet_bundle_sack(packet, chunk);
if (retval != SCTP_XMIT_OK)
goto finish;
+ psize = packet->size;
pmtu = ((packet->transport->asoc) ?
(packet->transport->asoc->pathmtu) :
(packet->transport->pathmtu));
@@ -241,10 +285,16 @@ sctp_xmit_t sctp_packet_append_chunk(struct sctp_packet *packet,
/* Decide if we need to fragment or resubmit later. */
if (too_big) {
- /* Both control chunks and data chunks with TSNs are
- * non-fragmentable.
+ /* It's OK to fragmet at IP level if any one of the following
+ * is true:
+ * 1. The packet is empty (meaning this chunk is greater
+ * the MTU)
+ * 2. The chunk we are adding is a control chunk
+ * 3. The packet doesn't have any data in it yet and data
+ * requires authentication.
*/
- if (sctp_packet_empty(packet) || !sctp_chunk_is_data(chunk)) {
+ if (sctp_packet_empty(packet) || !sctp_chunk_is_data(chunk) ||
+ (!packet->has_data && chunk->auth)) {
/* We no longer do re-fragmentation.
* Just fragment at the IP layer, if we
* actually hit this condition
@@ -266,16 +316,31 @@ append:
/* DATA is a special case since we must examine both rwnd and cwnd
* before we send DATA.
*/
- if (sctp_chunk_is_data(chunk)) {
+ switch (chunk->chunk_hdr->type) {
+ case SCTP_CID_DATA:
retval = sctp_packet_append_data(packet, chunk);
/* Disallow SACK bundling after DATA. */
packet->has_sack = 1;
+ /* Disallow AUTH bundling after DATA */
+ packet->has_auth = 1;
+ /* Let it be knows that packet has DATA in it */
+ packet->has_data = 1;
if (SCTP_XMIT_OK != retval)
goto finish;
- } else if (SCTP_CID_COOKIE_ECHO == chunk->chunk_hdr->type)
+ break;
+ case SCTP_CID_COOKIE_ECHO:
packet->has_cookie_echo = 1;
- else if (SCTP_CID_SACK == chunk->chunk_hdr->type)
+ break;
+
+ case SCTP_CID_SACK:
packet->has_sack = 1;
+ break;
+
+ case SCTP_CID_AUTH:
+ packet->has_auth = 1;
+ packet->auth = chunk;
+ break;
+ }
/* It is OK to send this chunk. */
list_add_tail(&chunk->list, &packet->chunk_list);
@@ -303,6 +368,8 @@ int sctp_packet_transmit(struct sctp_packet *packet)
int padding; /* How much padding do we need? */
__u8 has_data = 0;
struct dst_entry *dst = tp->dst;
+ unsigned char *auth = NULL; /* pointer to auth in skb data */
+ __u32 cksum_buf_len = sizeof(struct sctphdr);
SCTP_DEBUG_PRINTK("%s: packet:%p\n", __FUNCTION__, packet);
@@ -356,16 +423,6 @@ int sctp_packet_transmit(struct sctp_packet *packet)
sh->vtag = htonl(packet->vtag);
sh->checksum = 0;
- /* 2) Calculate the Adler-32 checksum of the whole packet,
- * including the SCTP common header and all the
- * chunks.
- *
- * Note: Adler-32 is no longer applicable, as has been replaced
- * by CRC32-C as described in <draft-ietf-tsvwg-sctpcsum-02.txt>.
- */
- if (!(dst->dev->features & NETIF_F_NO_CSUM))
- crc32 = sctp_start_cksum((__u8 *)sh, sizeof(struct sctphdr));
-
/**
* 6.10 Bundling
*
@@ -416,14 +473,16 @@ int sctp_packet_transmit(struct sctp_packet *packet)
if (padding)
memset(skb_put(chunk->skb, padding), 0, padding);
- if (dst->dev->features & NETIF_F_NO_CSUM)
- memcpy(skb_put(nskb, chunk->skb->len),
+ /* if this is the auth chunk that we are adding,
+ * store pointer where it will be added and put
+ * the auth into the packet.
+ */
+ if (chunk == packet->auth)
+ auth = skb_tail_pointer(nskb);
+
+ cksum_buf_len += chunk->skb->len;
+ memcpy(skb_put(nskb, chunk->skb->len),
chunk->skb->data, chunk->skb->len);
- else
- crc32 = sctp_update_copy_cksum(skb_put(nskb,
- chunk->skb->len),
- chunk->skb->data,
- chunk->skb->len, crc32);
SCTP_DEBUG_PRINTK("%s %p[%s] %s 0x%x, %s %d, %s %d, %s %d\n",
"*** Chunk", chunk,
@@ -445,9 +504,31 @@ int sctp_packet_transmit(struct sctp_packet *packet)
sctp_chunk_free(chunk);
}
- /* Perform final transformation on checksum. */
- if (!(dst->dev->features & NETIF_F_NO_CSUM))
+ /* SCTP-AUTH, Section 6.2
+ * The sender MUST calculate the MAC as described in RFC2104 [2]
+ * using the hash function H as described by the MAC Identifier and
+ * the shared association key K based on the endpoint pair shared key
+ * described by the shared key identifier. The 'data' used for the
+ * computation of the AUTH-chunk is given by the AUTH chunk with its
+ * HMAC field set to zero (as shown in Figure 6) followed by all
+ * chunks that are placed after the AUTH chunk in the SCTP packet.
+ */
+ if (auth)
+ sctp_auth_calculate_hmac(asoc, nskb,
+ (struct sctp_auth_chunk *)auth,
+ GFP_ATOMIC);
+
+ /* 2) Calculate the Adler-32 checksum of the whole packet,
+ * including the SCTP common header and all the
+ * chunks.
+ *
+ * Note: Adler-32 is no longer applicable, as has been replaced
+ * by CRC32-C as described in <draft-ietf-tsvwg-sctpcsum-02.txt>.
+ */
+ if (!(dst->dev->features & NETIF_F_NO_CSUM)) {
+ crc32 = sctp_start_cksum((__u8 *)sh, cksum_buf_len);
crc32 = sctp_end_cksum(crc32);
+ }
/* 3) Put the resultant value into the checksum field in the
* common header, and leave the rest of the bits unchanged.