summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authorrrs <rrs@FreeBSD.org>2007-02-12 23:24:31 +0000
committerrrs <rrs@FreeBSD.org>2007-02-12 23:24:31 +0000
commite176cc33f53a2dee7896aec59f970825b57845b8 (patch)
tree6152741c43ebcb3fc304c4834897a4966cc8bdbd /sys
parent725b149c2db3f8bc35268426a9c1719420d722fa (diff)
downloadFreeBSD-src-e176cc33f53a2dee7896aec59f970825b57845b8.zip
FreeBSD-src-e176cc33f53a2dee7896aec59f970825b57845b8.tar.gz
- Copyright updates (aka 2007)
- ZONE get now also take a type cast so it does the cast like mtod does. - New macro SCTP_LIST_EMPTY, which in bsd is just LIST_EMPTY - Removal of const in some of the static hmac functions (not needed) - Store length changes to allow for new fields in auth - Auth code updated to current draft (this should be the RFC version we think). - use uint8_t instead of u_char in LOOPBACK address comparison - Some u_int32_t converted to uint32_t (in crc code) - A bug was found in the mib counts for ordered/unordered count, this was fixed (was referencing a freed mbuf). - SCTP_ASOCLOG_OF_TSNS added (code will probably disappear after my testing completes. It allows us to keep a small log on each assoc of the last 40 TSN's in/out and stream assignment. It is NOT in options and so is only good for private builds. - Some CMT changes in prep for Jana fixing his problem with reneging when CMT is enabled (Concurrent Multipath Transfer = CMT). - Some missing mib stats added. - Correction to number of open assoc's count in mib - Correction to os_bsd.h to get right sha2 macros - Add of special AUTH_04 flags so you can compile the code with the old format (in case the peer does not yet support the latest auth code). - Nonce sum was incorrectly being set in when ecn_nonce was NOT on. - LOR in listen with implicit bind found and fixed. - Moved away from using mbuf's for socket options to using just data pointers. The mbufs were used to harmonize NetBSD code since both Net and Open used this method. We have decided to move away from that and more conform to FreeBSD style (which makes more sense). - Very very nasty bug found in some of my "debug" code. The cookie_how collision case tracking had an endless loop in it if you got a second retransmission of a cookie collision case. This would lock up a CPU .. ugly.. - auth function goes to using size_t instead of int which conforms to socketapi better - Found the nasty bug that happens after 9 days of testing.. you get the data chunk, deliver it and due to the reference to a ch-> that every now and then has been deleted (depending on the postion in the mbuf) you have an invalid ch->ch.flags.. and thus you don't advance the stream sequence number.. so you block the stream permanently. The fix is to make local variables of these guys and set them up before you have any chance of trimming the mbuf. - style fix in sctp_util.h, not sure how this got bad maybe in the last patch? (aka it may not be in the real source). - Found interesting bug when using the extended snd/rcv info where we would get an error on receiving with this. Thats because it was NOT padded to the same size as the snd_rcv info. We increase (add the pad) so the two structs are the same size in sctp_uio.h - In sctp_usrreq.c one of the most common things we did for socket options was to cast the pointer and validate the size. This as been macro-ized to help make the code more readable. - in sctputil.c two things, the socketapi class found a missing flag type (the next msg is a notification) and a missing scope recovery was also fixed. Reviewed by: gnn
Diffstat (limited to 'sys')
-rw-r--r--sys/netinet/sctp_asconf.c8
-rw-r--r--sys/netinet/sctp_auth.c99
-rw-r--r--sys/netinet/sctp_auth.h41
-rw-r--r--sys/netinet/sctp_constants.h32
-rw-r--r--sys/netinet/sctp_crc32.c9
-rw-r--r--sys/netinet/sctp_indata.c158
-rw-r--r--sys/netinet/sctp_input.c60
-rw-r--r--sys/netinet/sctp_os.h5
-rw-r--r--sys/netinet/sctp_os_bsd.h35
-rw-r--r--sys/netinet/sctp_output.c56
-rw-r--r--sys/netinet/sctp_pcb.c77
-rw-r--r--sys/netinet/sctp_peeloff.c2
-rw-r--r--sys/netinet/sctp_structs.h32
-rw-r--r--sys/netinet/sctp_timer.c13
-rw-r--r--sys/netinet/sctp_uio.h52
-rw-r--r--sys/netinet/sctp_usrreq.c1800
-rw-r--r--sys/netinet/sctp_var.h160
-rw-r--r--sys/netinet/sctputil.c40
-rw-r--r--sys/netinet/sctputil.h30
-rw-r--r--sys/netinet6/sctp6_usrreq.c9
20 files changed, 1181 insertions, 1537 deletions
diff --git a/sys/netinet/sctp_asconf.c b/sys/netinet/sctp_asconf.c
index 500d2eb..8abab9d 100644
--- a/sys/netinet/sctp_asconf.c
+++ b/sys/netinet/sctp_asconf.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2001-2006, Cisco Systems, Inc. All rights reserved.
+ * Copyright (c) 2001-2007, Cisco Systems, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -653,7 +653,7 @@ sctp_handle_asconf(struct mbuf *m, unsigned int offset,
int error = 0; /* did an error occur? */
/* asconf param buffer */
- static uint8_t aparam_buf[DEFAULT_PARAM_BUFFER];
+ uint8_t aparam_buf[SCTP_PARAM_BUFFER_SIZE];
/* verify minimum length */
if (ntohs(cp->ch.chunk_length) < sizeof(struct sctp_asconf_chunk)) {
@@ -1401,7 +1401,7 @@ sctp_handle_asconf_ack(struct mbuf *m, int offset,
struct sctp_asconf_addr *ap;
/* asconf param buffer */
- static uint8_t aparam_buf[DEFAULT_PARAM_BUFFER];
+ uint8_t aparam_buf[SCTP_PARAM_BUFFER_SIZE];
/* verify minimum length */
if (ntohs(cp->ch.chunk_length) < sizeof(struct sctp_asconf_ack_chunk)) {
@@ -2774,7 +2774,7 @@ sctp_addr_change(struct ifaddr *ifa, int cmd)
{
struct sctp_laddr *wi;
- wi = (struct sctp_laddr *)SCTP_ZONE_GET(sctppcbinfo.ipi_zone_laddr);
+ wi = SCTP_ZONE_GET(sctppcbinfo.ipi_zone_laddr, struct sctp_laddr);
if (wi == NULL) {
/*
* Gak, what can we do? We have lost an address change can
diff --git a/sys/netinet/sctp_auth.c b/sys/netinet/sctp_auth.c
index 6c7572f..86df162 100644
--- a/sys/netinet/sctp_auth.c
+++ b/sys/netinet/sctp_auth.c
@@ -155,7 +155,7 @@ sctp_auth_delete_chunk(uint8_t chunk, sctp_auth_chklist_t * list)
return (0);
}
-inline int
+inline size_t
sctp_auth_get_chklist_size(const sctp_auth_chklist_t * list)
{
if (list == NULL)
@@ -543,7 +543,7 @@ sctp_insert_sharedkey(struct sctp_keyhead *shared_keys,
return;
/* insert into an empty list? */
- if (LIST_EMPTY(shared_keys)) {
+ if (SCTP_LIST_EMPTY(shared_keys)) {
LIST_INSERT_HEAD(shared_keys, new_skey, next);
return;
}
@@ -903,7 +903,7 @@ sctp_hmac_init(uint16_t hmac_algo, sctp_hash_context_t * ctx)
static void
sctp_hmac_update(uint16_t hmac_algo, sctp_hash_context_t * ctx,
- const uint8_t * text, uint32_t textlen)
+ uint8_t * text, uint32_t textlen)
{
switch (hmac_algo) {
case SCTP_AUTH_HMAC_ID_SHA1:
@@ -980,7 +980,7 @@ sctp_hmac_final(uint16_t hmac_algo, sctp_hash_context_t * ctx,
*/
uint32_t
sctp_hmac(uint16_t hmac_algo, uint8_t * key, uint32_t keylen,
- const uint8_t * text, uint32_t textlen, uint8_t * digest)
+ uint8_t * text, uint32_t textlen, uint8_t * digest)
{
uint32_t digestlen;
uint32_t blocklen;
@@ -1117,7 +1117,7 @@ sctp_hmac_m(uint16_t hmac_algo, uint8_t * key, uint32_t keylen,
*/
int
sctp_verify_hmac(uint16_t hmac_algo, uint8_t * key, uint32_t keylen,
- const uint8_t * text, uint32_t textlen,
+ uint8_t * text, uint32_t textlen,
uint8_t * digest, uint32_t digestlen)
{
uint32_t len;
@@ -1149,7 +1149,7 @@ sctp_verify_hmac(uint16_t hmac_algo, uint8_t * key, uint32_t keylen,
* the keylen exceeds the HMAC block len).
*/
uint32_t
-sctp_compute_hmac(uint16_t hmac_algo, sctp_key_t * key, const uint8_t * text,
+sctp_compute_hmac(uint16_t hmac_algo, sctp_key_t * key, uint8_t * text,
uint32_t textlen, uint8_t * digest)
{
uint32_t digestlen;
@@ -1413,11 +1413,13 @@ sctp_auth_get_cookie_params(struct sctp_tcb *stcb, struct mbuf *m,
{
struct sctp_paramhdr *phdr, tmp_param;
uint16_t plen, ptype;
- uint8_t store[384];
+ uint8_t random_store[SCTP_PARAM_BUFFER_SIZE];
struct sctp_auth_random *random = NULL;
uint16_t random_len = 0;
+ uint8_t hmacs_store[SCTP_PARAM_BUFFER_SIZE];
struct sctp_auth_hmac_algo *hmacs = NULL;
uint16_t hmacs_len = 0;
+ uint8_t chunks_store[SCTP_PARAM_BUFFER_SIZE];
struct sctp_auth_chunk_list *chunks = NULL;
uint16_t num_chunks = 0;
sctp_key_t *new_key;
@@ -1436,10 +1438,10 @@ sctp_auth_get_cookie_params(struct sctp_tcb *stcb, struct mbuf *m,
break;
if (ptype == SCTP_RANDOM) {
- if (plen > sizeof(store))
+ if (plen > sizeof(random_store))
break;
phdr = sctp_get_next_param(m, offset,
- (struct sctp_paramhdr *)store, plen);
+ (struct sctp_paramhdr *)random_store, plen);
if (phdr == NULL)
return;
/* save the random and length for the key */
@@ -1449,10 +1451,10 @@ sctp_auth_get_cookie_params(struct sctp_tcb *stcb, struct mbuf *m,
int num_hmacs;
int i;
- if (plen > sizeof(store))
+ if (plen > sizeof(hmacs_store))
break;
phdr = sctp_get_next_param(m, offset,
- (struct sctp_paramhdr *)store, plen);
+ (struct sctp_paramhdr *)hmacs_store, plen);
if (phdr == NULL)
return;
/* save the hmacs list and num for the key */
@@ -1471,10 +1473,10 @@ sctp_auth_get_cookie_params(struct sctp_tcb *stcb, struct mbuf *m,
} else if (ptype == SCTP_CHUNK_LIST) {
int i;
- if (plen > sizeof(store))
+ if (plen > sizeof(chunks_store))
break;
phdr = sctp_get_next_param(m, offset,
- (struct sctp_paramhdr *)store, plen);
+ (struct sctp_paramhdr *)chunks_store, plen);
if (phdr == NULL)
return;
chunks = (struct sctp_auth_chunk_list *)phdr;
@@ -1497,21 +1499,37 @@ sctp_auth_get_cookie_params(struct sctp_tcb *stcb, struct mbuf *m,
(uint8_t *) & tmp_param);
}
/* concatenate the full random key */
- keylen = random_len + num_chunks + hmacs_len;
+#ifdef SCTP_AUTH_DRAFT_04
+ keylen = random_len;
new_key = sctp_alloc_key(keylen);
if (new_key != NULL) {
/* copy in the RANDOM */
if (random != NULL)
bcopy(random->random_data, new_key->key, random_len);
+ }
+#else
+ keylen = sizeof(*random) + random_len + sizeof(*chunks) + num_chunks +
+ sizeof(*hmacs) + hmacs_len;
+ new_key = sctp_alloc_key(keylen);
+ if (new_key != NULL) {
+ /* copy in the RANDOM */
+ if (random != NULL) {
+ keylen = sizeof(*random) + random_len;
+ bcopy(random, new_key->key, keylen);
+ }
/* append in the AUTH chunks */
- if (chunks != NULL)
- bcopy(chunks->chunk_types, new_key->key + random_len,
- num_chunks);
+ if (chunks != NULL) {
+ bcopy(chunks, new_key->key + keylen,
+ sizeof(*chunks) + num_chunks);
+ keylen += sizeof(*chunks) + num_chunks;
+ }
/* append in the HMACs */
- if (hmacs != NULL)
- bcopy(hmacs->hmac_ids, new_key->key + random_len + num_chunks,
- hmacs_len);
+ if (hmacs != NULL) {
+ bcopy(hmacs, new_key->key + keylen,
+ sizeof(*hmacs) + hmacs_len);
+ }
}
+#endif
if (stcb->asoc.authinfo.random != NULL)
sctp_free_key(stcb->asoc.authinfo.random);
stcb->asoc.authinfo.random = new_key;
@@ -1829,7 +1847,7 @@ sctp_validate_init_auth_params(struct mbuf *m, int offset, int limit)
if (ptype == SCTP_SUPPORTED_CHUNK_EXT) {
/* A supported extension chunk */
struct sctp_supported_chunk_types_param *pr_supported;
- uint8_t local_store[128];
+ uint8_t local_store[SCTP_PARAM_BUFFER_SIZE];
int num_ent, i;
phdr = sctp_get_next_param(m, offset,
@@ -1865,7 +1883,7 @@ sctp_validate_init_auth_params(struct mbuf *m, int offset, int limit)
return (-1);
}
} else if (ptype == SCTP_HMAC_LIST) {
- uint8_t store[256];
+ uint8_t store[SCTP_PARAM_BUFFER_SIZE];
struct sctp_auth_hmac_algo *hmacs;
int num_hmacs;
@@ -1942,13 +1960,34 @@ sctp_initialize_auth_params(struct sctp_inpcb *inp, struct sctp_tcb *stcb)
stcb->asoc.authinfo.assoc_keyid = inp->sctp_ep.default_keyid;
/* now set the concatenated key (random + chunks + hmacs) */
- keylen = random_len + chunks_len + hmacs_len;
+#ifdef SCTP_AUTH_DRAFT_04
+ /* don't include the chunks and hmacs for draft -04 */
+ keylen = random_len;
+ new_key = sctp_generate_random_key(keylen);
+#else
+ /* key includes parameter headers */
+ keylen = (3 * sizeof(struct sctp_paramhdr)) + random_len + chunks_len +
+ hmacs_len;
new_key = sctp_alloc_key(keylen);
if (new_key != NULL) {
+ struct sctp_paramhdr *ph;
+ int plen;
+
/* generate and copy in the RANDOM */
- SCTP_READ_RANDOM(new_key->key, random_len);
- keylen = random_len;
+ ph = (struct sctp_paramhdr *)new_key->key;
+ ph->param_type = htons(SCTP_RANDOM);
+ plen = sizeof(*ph) + random_len;
+ ph->param_length = htons(plen);
+ SCTP_READ_RANDOM(new_key->key + sizeof(*ph), random_len);
+ keylen = plen;
+
/* append in the AUTH chunks */
+ /* NOTE: currently we always have chunks to list */
+ ph = (struct sctp_paramhdr *)(new_key->key + keylen);
+ ph->param_type = htons(SCTP_CHUNK_LIST);
+ plen = sizeof(*ph) + chunks_len;
+ ph->param_length = htons(plen);
+ keylen += sizeof(*ph);
if (stcb->asoc.local_auth_chunks) {
int i;
@@ -1958,17 +1997,19 @@ sctp_initialize_auth_params(struct sctp_inpcb *inp, struct sctp_tcb *stcb)
}
}
/* append in the HMACs */
+ ph = (struct sctp_paramhdr *)(new_key->key + keylen);
+ ph->param_type = htons(SCTP_HMAC_LIST);
+ plen = sizeof(*ph) + hmacs_len;
+ ph->param_length = htons(plen);
+ keylen += sizeof(*ph);
sctp_serialize_hmaclist(stcb->asoc.local_hmacs,
new_key->key + keylen);
}
+#endif
if (stcb->asoc.authinfo.random != NULL)
sctp_free_key(stcb->asoc.authinfo.random);
stcb->asoc.authinfo.random = new_key;
stcb->asoc.authinfo.random_len = random_len;
-#ifdef SCTP_AUTH_DRAFT_04
- /* don't include the chunks and hmacs for draft -04 */
- stcb->asoc.authinfo.random->keylen = random_len;
-#endif
}
diff --git a/sys/netinet/sctp_auth.h b/sys/netinet/sctp_auth.h
index c6eb88a..5d0f4da 100644
--- a/sys/netinet/sctp_auth.h
+++ b/sys/netinet/sctp_auth.h
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2001-2006, Cisco Systems, Inc. All rights reserved.
+ * Copyright (c) 2001-2007, Cisco Systems, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -30,33 +30,10 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
-#define HAVE_SHA2
#ifndef __SCTP_AUTH_H__
#define __SCTP_AUTH_H__
-#include <sys/queue.h>
-#include <sys/mbuf.h>
-
-#ifdef USE_SCTP_SHA1
-#include <netinet/sctp_sha1.h>
-#else
-#include <crypto/sha1.h>
-/* map standard crypto API names */
-#define SHA1_Init SHA1Init
-#define SHA1_Update SHA1Update
-#define SHA1_Final(x,y) SHA1Final((caddr_t)x, y)
-#endif
-
-#if defined(HAVE_SHA2)
-#include <crypto/sha2/sha2.h>
-#endif
-
-#include <sys/md5.h>
-/* map standard crypto API names */
-#define MD5_Init MD5Init
-#define MD5_Update MD5Update
-#define MD5_Final MD5Final
/* digest lengths */
#define SCTP_AUTH_DIGEST_LEN_SHA1 20
@@ -145,11 +122,10 @@ extern void sctp_clear_chunklist(sctp_auth_chklist_t * chklist);
extern sctp_auth_chklist_t *sctp_copy_chunklist(sctp_auth_chklist_t * chklist);
extern int sctp_auth_add_chunk(uint8_t chunk, sctp_auth_chklist_t * list);
extern int sctp_auth_delete_chunk(uint8_t chunk, sctp_auth_chklist_t * list);
-extern int sctp_auth_get_chklist_size(const sctp_auth_chklist_t * list);
+extern size_t sctp_auth_get_chklist_size(const sctp_auth_chklist_t * list);
extern void sctp_auth_set_default_chunks(sctp_auth_chklist_t * list);
extern int
-sctp_serialize_auth_chunks(const sctp_auth_chklist_t * list,
- uint8_t * ptr);
+ sctp_serialize_auth_chunks(const sctp_auth_chklist_t * list, uint8_t * ptr);
extern int sctp_pack_auth_chunks(const sctp_auth_chklist_t * list, uint8_t * ptr);
extern int
sctp_unpack_auth_chunks(const uint8_t * ptr, uint8_t num_chunks,
@@ -170,8 +146,7 @@ sctp_compute_hashkey(sctp_key_t * key1, sctp_key_t * key2,
extern sctp_sharedkey_t *sctp_alloc_sharedkey(void);
extern void sctp_free_sharedkey(sctp_sharedkey_t * skey);
extern sctp_sharedkey_t *
-sctp_find_sharedkey(struct sctp_keyhead *shared_keys,
- uint16_t key_id);
+ sctp_find_sharedkey(struct sctp_keyhead *shared_keys, uint16_t key_id);
extern void
sctp_insert_sharedkey(struct sctp_keyhead *shared_keys,
sctp_sharedkey_t * new_skey);
@@ -185,7 +160,7 @@ extern void sctp_free_hmaclist(sctp_hmaclist_t * list);
extern int sctp_auth_add_hmacid(sctp_hmaclist_t * list, uint16_t hmac_id);
extern sctp_hmaclist_t *sctp_copy_hmaclist(sctp_hmaclist_t * list);
extern sctp_hmaclist_t *sctp_default_supported_hmaclist(void);
-extern uint16_t
+extern uint16_t
sctp_negotiate_hmacid(sctp_hmaclist_t * peer,
sctp_hmaclist_t * local);
extern int sctp_serialize_hmaclist(sctp_hmaclist_t * list, uint8_t * ptr);
@@ -201,14 +176,14 @@ extern uint32_t sctp_get_auth_chunk_len(uint16_t hmac_algo);
extern uint32_t sctp_get_hmac_digest_len(uint16_t hmac_algo);
extern uint32_t
sctp_hmac(uint16_t hmac_algo, uint8_t * key, uint32_t keylen,
- const uint8_t * text, uint32_t textlen, uint8_t * digest);
+ uint8_t * text, uint32_t textlen, uint8_t * digest);
extern int
sctp_verify_hmac(uint16_t hmac_algo, uint8_t * key, uint32_t keylen,
- const uint8_t * text, uint32_t textlen, uint8_t * digest,
+ uint8_t * text, uint32_t textlen, uint8_t * digest,
uint32_t digestlen);
extern uint32_t
sctp_compute_hmac(uint16_t hmac_algo, sctp_key_t * key,
- const uint8_t * text, uint32_t textlen, uint8_t * digest);
+ uint8_t * text, uint32_t textlen, uint8_t * digest);
extern int sctp_auth_is_supported_hmac(sctp_hmaclist_t * list, uint16_t id);
/* mbuf versions */
diff --git a/sys/netinet/sctp_constants.h b/sys/netinet/sctp_constants.h
index 9d23e4f..dcb05af 100644
--- a/sys/netinet/sctp_constants.h
+++ b/sys/netinet/sctp_constants.h
@@ -36,10 +36,6 @@ __FBSDID("$FreeBSD$");
#ifndef __sctp_constants_h__
#define __sctp_constants_h__
-#if defined(_KERNEL)
-#include <sys/kernel.h>
-#endif
-
#define SCTP_VERSION_STRING "KAME-BSD 1.1"
/* #define SCTP_AUDITING_ENABLED 1 used for debug/auditing */
@@ -556,7 +552,7 @@ __FBSDID("$FreeBSD$");
#define SCTP_ASOC_MAX_CHUNKS_ON_QUEUE 512
#define MSEC_TO_TICKS(x) ((hz == 1000) ? x : (((x) * hz) / 1000))
-#define TICKS_TO_MSEC(x) ((hz == 1000) ? x : (((x) * 1000) / hz));
+#define TICKS_TO_MSEC(x) ((hz == 1000) ? x : (((x) * 1000) / hz))
#define SEC_TO_TICKS(x) ((x) * hz)
#define TICKS_TO_SEC(x) ((x) / hz)
@@ -689,8 +685,8 @@ __FBSDID("$FreeBSD$");
#define SCTP_DEFAULT_MAXSEGMENT 65535
-#define DEFAULT_CHUNK_BUFFER 2048
-#define DEFAULT_PARAM_BUFFER 512
+#define SCTP_CHUNK_BUFFER_SIZE 2048
+#define SCTP_PARAM_BUFFER_SIZE 512
#define SCTP_DEFAULT_MINSEGMENT 512 /* MTU size ... if no mtu disc */
#define SCTP_HOW_MANY_SECRETS 2 /* how many secrets I keep */
@@ -908,20 +904,19 @@ __FBSDID("$FreeBSD$");
#define SCTP_DEF_SYSTEM_RESC_LIMIT 1000
-
#define IN4_ISPRIVATE_ADDRESS(a) \
- ((((u_char *)&(a)->s_addr)[0] == 10) || \
- ((((u_char *)&(a)->s_addr)[0] == 172) && \
- (((u_char *)&(a)->s_addr)[1] >= 16) && \
- (((u_char *)&(a)->s_addr)[1] <= 32)) || \
- ((((u_char *)&(a)->s_addr)[0] == 192) && \
- (((u_char *)&(a)->s_addr)[1] == 168)))
+ ((((uint8_t *)&(a)->s_addr)[0] == 10) || \
+ ((((uint8_t *)&(a)->s_addr)[0] == 172) && \
+ (((uint8_t *)&(a)->s_addr)[1] >= 16) && \
+ (((uint8_t *)&(a)->s_addr)[1] <= 32)) || \
+ ((((uint8_t *)&(a)->s_addr)[0] == 192) && \
+ (((uint8_t *)&(a)->s_addr)[1] == 168)))
#define IN4_ISLOOPBACK_ADDRESS(a) \
- ((((u_char *)&(a)->s_addr)[0] == 127) && \
- (((u_char *)&(a)->s_addr)[1] == 0) && \
- (((u_char *)&(a)->s_addr)[2] == 0) && \
- (((u_char *)&(a)->s_addr)[3] == 1))
+ ((((uint8_t *)&(a)->s_addr)[0] == 127) && \
+ (((uint8_t *)&(a)->s_addr)[1] == 0) && \
+ (((uint8_t *)&(a)->s_addr)[2] == 0) && \
+ (((uint8_t *)&(a)->s_addr)[3] == 1))
#if defined(_KERNEL)
@@ -966,7 +961,6 @@ do { \
} \
} while (0)
-/* FIXME */
#define sctp_sorwakeup_locked(inp, so) \
do { \
if (inp->sctp_flags & SCTP_PCB_FLAGS_DONT_WAKE) { \
diff --git a/sys/netinet/sctp_crc32.c b/sys/netinet/sctp_crc32.c
index 3728ef3..47f5483 100644
--- a/sys/netinet/sctp_crc32.c
+++ b/sys/netinet/sctp_crc32.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2001-2006, Cisco Systems, Inc. All rights reserved.
+ * Copyright (c) 2001-2007, Cisco Systems, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -34,8 +34,7 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
-#include "opt_sctp.h"
-#include <sys/param.h>
+#include <netinet/sctp_os.h>
#include <netinet/sctp_crc32.h>
#ifndef SCTP_USE_ADLER32
@@ -663,8 +662,8 @@ uint32_t sctp_crc_c[256] = {
#define SCTP_CRC32C(c,d) (c=(c>>8)^sctp_crc_c[(c^(d))&0xFF])
-u_int32_t
-old_update_crc32(u_int32_t crc32,
+uint32_t
+old_update_crc32(uint32_t crc32,
unsigned char *buffer,
unsigned int length)
{
diff --git a/sys/netinet/sctp_indata.c b/sys/netinet/sctp_indata.c
index 97dcfab..86945f7 100644
--- a/sys/netinet/sctp_indata.c
+++ b/sys/netinet/sctp_indata.c
@@ -321,13 +321,12 @@ sctp_service_reassembly(struct sctp_tcb *stcb, struct sctp_association *asoc)
uint16_t stream_no;
int end = 0;
int cntDel;
-
- cntDel = stream_no = 0;
struct sctp_queued_to_read *control, *ctl, *ctlat;
- if (stcb && ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) ||
- (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET))
- ) {
+ cntDel = stream_no = 0;
+ if (stcb &&
+ ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) ||
+ (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET))) {
/* socket above is long gone */
asoc->fragmented_delivery_inprogress = 0;
chk = TAILQ_FIRST(&asoc->reasmqueue);
@@ -1456,9 +1455,15 @@ sctp_process_a_data_chunk(struct sctp_tcb *stcb, struct sctp_association *asoc,
uint16_t strmno, strmseq;
struct mbuf *oper;
struct sctp_queued_to_read *control;
+ int ordered;
+ uint32_t protocol_id;
+ uint8_t chunk_flags;
chk = NULL;
tsn = ntohl(ch->dp.tsn);
+ chunk_flags = ch->ch.chunk_flags;
+ protocol_id = ch->dp.protocol_id;
+ ordered = ((ch->ch.chunk_flags & SCTP_DATA_UNORDERED) == 0);
#ifdef SCTP_MAP_LOGGING
sctp_log_map(0, tsn, asoc->cumulative_tsn, SCTP_MAP_PREPARE_SLIDE);
#endif
@@ -1613,8 +1618,18 @@ sctp_process_a_data_chunk(struct sctp_tcb *stcb, struct sctp_association *asoc,
* only validate the FIRST fragment so the bit must be set.
*/
strmseq = ntohs(ch->dp.stream_sequence);
- if ((ch->ch.chunk_flags & SCTP_DATA_FIRST_FRAG) &&
- (ch->ch.chunk_flags & SCTP_DATA_UNORDERED) == 0 &&
+
+#ifdef SCTP_ASOCLOG_OF_TSNS
+ asoc->in_tsnlog[asoc->tsn_in_at].tsn = tsn;
+ asoc->in_tsnlog[asoc->tsn_in_at].strm = strmno;
+ asoc->in_tsnlog[asoc->tsn_in_at].seq = strmseq;
+ asoc->tsn_in_at++;
+ if (asoc->tsn_in_at >= SCTP_TSN_LOG_SIZE) {
+ asoc->tsn_in_at = 0;
+ }
+#endif
+ if ((chunk_flags & SCTP_DATA_FIRST_FRAG) &&
+ (chunk_flags & SCTP_DATA_UNORDERED) == 0 &&
(compare_with_wrap(asoc->strmin[strmno].last_sequence_delivered,
strmseq, MAX_SEQ) ||
asoc->strmin[strmno].last_sequence_delivered == strmseq)) {
@@ -1655,6 +1670,11 @@ sctp_process_a_data_chunk(struct sctp_tcb *stcb, struct sctp_association *asoc,
*abort_flag = 1;
return (0);
}
+ /************************************
+ * From here down we may find ch-> invalid
+ * so its a good idea NOT to use it.
+ *************************************/
+
the_len = (chk_length - sizeof(struct sctp_data_chunk));
if (last_chunk == 0) {
dmbuf = SCTP_M_COPYM(*m,
@@ -1705,10 +1725,10 @@ sctp_process_a_data_chunk(struct sctp_tcb *stcb, struct sctp_association *asoc,
SCTP_STAT_INCR(sctps_nomem);
return (0);
}
- if ((ch->ch.chunk_flags & SCTP_DATA_NOT_FRAG) == SCTP_DATA_NOT_FRAG &&
+ if ((chunk_flags & SCTP_DATA_NOT_FRAG) == SCTP_DATA_NOT_FRAG &&
asoc->fragmented_delivery_inprogress == 0 &&
TAILQ_EMPTY(&asoc->resetHead) &&
- ((ch->ch.chunk_flags & SCTP_DATA_UNORDERED) ||
+ ((ordered == 0) ||
((asoc->strmin[strmno].last_sequence_delivered + 1) == strmseq &&
TAILQ_EMPTY(&asoc->strmin[strmno].inqueue)))) {
/* Candidate for express delivery */
@@ -1723,16 +1743,16 @@ sctp_process_a_data_chunk(struct sctp_tcb *stcb, struct sctp_association *asoc,
/* It would be nice to avoid this copy if we could :< */
sctp_alloc_a_readq(stcb, control);
sctp_build_readq_entry_mac(control, stcb, asoc->context, net, tsn,
- ch->dp.protocol_id,
+ protocol_id,
stcb->asoc.context,
strmno, strmseq,
- ch->ch.chunk_flags,
+ chunk_flags,
dmbuf);
if (control == NULL) {
goto failed_express_del;
}
sctp_add_to_readq(stcb->sctp_ep, stcb, control, &stcb->sctp_socket->so_rcv, 1);
- if ((ch->ch.chunk_flags & SCTP_DATA_UNORDERED) == 0) {
+ if ((chunk_flags & SCTP_DATA_UNORDERED) == 0) {
/* for ordered, bump what we delivered */
asoc->strmin[strmno].last_sequence_delivered++;
}
@@ -1755,7 +1775,7 @@ failed_express_del:
(asoc->ssn_of_pdapi == strmseq)
) {
control = stcb->asoc.control_pdapi;
- if ((ch->ch.chunk_flags & SCTP_DATA_FIRST_FRAG) == SCTP_DATA_FIRST_FRAG) {
+ if ((chunk_flags & SCTP_DATA_FIRST_FRAG) == SCTP_DATA_FIRST_FRAG) {
/* Can't be another first? */
goto failed_pdapi_express_del;
}
@@ -1764,7 +1784,7 @@ failed_express_del:
int end = 0;
uint32_t cumack;
- if (ch->ch.chunk_flags & SCTP_DATA_LAST_FRAG) {
+ if (chunk_flags & SCTP_DATA_LAST_FRAG) {
end = 1;
}
cumack = asoc->cumulative_tsn;
@@ -1780,15 +1800,15 @@ failed_express_del:
SCTP_STAT_INCR(sctps_recvexpressm);
control->sinfo_tsn = tsn;
asoc->tsn_last_delivered = tsn;
- asoc->fragment_flags = ch->ch.chunk_flags;
+ asoc->fragment_flags = chunk_flags;
asoc->tsn_of_pdapi_last_delivered = tsn;
- asoc->last_flags_delivered = ch->ch.chunk_flags;
+ asoc->last_flags_delivered = chunk_flags;
asoc->last_strm_seq_delivered = strmseq;
asoc->last_strm_no_delivered = strmno;
if (end) {
/* clean up the flags and such */
asoc->fragmented_delivery_inprogress = 0;
- if ((ch->ch.chunk_flags & SCTP_DATA_UNORDERED) == 0) {
+ if ((chunk_flags & SCTP_DATA_UNORDERED) == 0) {
asoc->strmin[strmno].last_sequence_delivered++;
}
stcb->asoc.control_pdapi = NULL;
@@ -1806,7 +1826,7 @@ failed_express_del:
}
failed_pdapi_express_del:
control = NULL;
- if ((ch->ch.chunk_flags & SCTP_DATA_NOT_FRAG) != SCTP_DATA_NOT_FRAG) {
+ if ((chunk_flags & SCTP_DATA_NOT_FRAG) != SCTP_DATA_NOT_FRAG) {
sctp_alloc_a_chunk(stcb, chk);
if (chk == NULL) {
/* No memory so we drop the chunk */
@@ -1821,10 +1841,10 @@ failed_pdapi_express_del:
chk->no_fr_allowed = 0;
chk->rec.data.stream_seq = strmseq;
chk->rec.data.stream_number = strmno;
- chk->rec.data.payloadtype = ch->dp.protocol_id;
+ chk->rec.data.payloadtype = protocol_id;
chk->rec.data.context = stcb->asoc.context;
chk->rec.data.doing_fast_retransmit = 0;
- chk->rec.data.rcv_flags = ch->ch.chunk_flags;
+ chk->rec.data.rcv_flags = chunk_flags;
chk->asoc = asoc;
chk->send_size = the_len;
chk->whoTo = net;
@@ -1833,10 +1853,10 @@ failed_pdapi_express_del:
} else {
sctp_alloc_a_readq(stcb, control);
sctp_build_readq_entry_mac(control, stcb, asoc->context, net, tsn,
- ch->dp.protocol_id,
+ protocol_id,
stcb->asoc.context,
strmno, strmseq,
- ch->ch.chunk_flags,
+ chunk_flags,
dmbuf);
if (control == NULL) {
/* No memory so we drop the chunk */
@@ -1980,7 +2000,7 @@ failed_pdapi_express_del:
}
}
/* ok, if we reach here we have passed the sanity checks */
- if (ch->ch.chunk_flags & SCTP_DATA_UNORDERED) {
+ if (chunk_flags & SCTP_DATA_UNORDERED) {
/* queue directly into socket buffer */
sctp_add_to_readq(stcb->sctp_ep, stcb,
control,
@@ -2073,7 +2093,7 @@ finish_express_del:
if (last_chunk) {
*m = NULL;
}
- if ((ch->ch.chunk_flags & SCTP_DATA_UNORDERED) == 0) {
+ if (ordered) {
SCTP_STAT_INCR_COUNTER64(sctps_inorderchunks);
} else {
SCTP_STAT_INCR_COUNTER64(sctps_inunorderchunks);
@@ -2401,9 +2421,8 @@ sctp_sack_check(struct sctp_tcb *stcb, int ok_to_sack, int was_a_gap, int *abort
* duplicates.
*/
stcb->asoc.first_ack_sent = 1;
-
+ SCTP_OS_TIMER_STOP(&stcb->asoc.dack_timer.timer);
sctp_send_sack(stcb);
- /* The sending will stop the timer */
}
} else {
sctp_timer_start(SCTP_TIMER_TYPE_RECV,
@@ -2908,7 +2927,7 @@ sctp_handle_segments(struct sctp_tcb *stcb, struct sctp_association *asoc,
* newly acked.
* update
* this_sack_highest_
- * n ewack if
+ * newack if
* appropriate.
*/
if (tp1->rec.data.chunk_was_revoked == 0)
@@ -2924,7 +2943,7 @@ sctp_handle_segments(struct sctp_tcb *stcb, struct sctp_association *asoc,
* CMT DAC algo:
* also update
* this_sack_lowest_n
- * e wack
+ * ewack
*/
if (*this_sack_lowest_newack == 0) {
#ifdef SCTP_SACK_LOGGING
@@ -2946,9 +2965,9 @@ sctp_handle_segments(struct sctp_tcb *stcb, struct sctp_association *asoc,
* acked, then we
* have a new
* (rtx-)pseudo-cumac
- * k . Set
+ * k. Set
* new_(rtx_)pseudo_c
- * u mack to TRUE so
+ * umack to TRUE so
* that the cwnd for
* this dest can be
* updated. Also
@@ -2956,7 +2975,7 @@ sctp_handle_segments(struct sctp_tcb *stcb, struct sctp_association *asoc,
* for the next
* expected
* (rtx-)pseudo-cumac
- * k . Separate
+ * k. Separate
* pseudo_cumack
* trackers for
* first
@@ -3089,24 +3108,43 @@ sctp_check_for_revoked(struct sctp_association *asoc, uint32_t cumack,
*/
if (tp1->sent == SCTP_DATAGRAM_ACKED) {
/* it has been revoked */
- tp1->sent = SCTP_DATAGRAM_SENT;
- tp1->rec.data.chunk_was_revoked = 1;
- /*
- * We must add this stuff back in to assure
- * timers and such get started.
- */
- tp1->whoTo->flight_size += tp1->book_size;
- asoc->total_flight_count++;
- asoc->total_flight += tp1->book_size;
- tot_revoked++;
+
+ if (sctp_cmt_on_off) {
+ /*
+ * If CMT is ON, leave "sent" at
+ * ACKED. CMT causes reordering of
+ * data and acks (received on
+ * different interfaces) can be
+ * persistently reordered. Acking
+ * followed by apparent revoking and
+ * re-acking causes unexpected weird
+ * behavior. So, at this time, CMT
+ * does not respect renegs. Renegs
+ * cannot be recovered. I will fix
+ * this once I am sure that things
+ * are working right again with CMT.
+ */
+ } else {
+ tp1->sent = SCTP_DATAGRAM_SENT;
+ tp1->rec.data.chunk_was_revoked = 1;
+ /*
+ * We must add this stuff back in to
+ * assure timers and such get
+ * started.
+ */
+ tp1->whoTo->flight_size += tp1->book_size;
+ asoc->total_flight_count++;
+ asoc->total_flight += tp1->book_size;
+ tot_revoked++;
#ifdef SCTP_SACK_LOGGING
- sctp_log_sack(asoc->last_acked_seq,
- cumack,
- tp1->rec.data.TSN_seq,
- 0,
- 0,
- SCTP_LOG_TSN_REVOKED);
+ sctp_log_sack(asoc->last_acked_seq,
+ cumack,
+ tp1->rec.data.TSN_seq,
+ 0,
+ 0,
+ SCTP_LOG_TSN_REVOKED);
#endif
+ }
} else if (tp1->sent == SCTP_DATAGRAM_MARKED) {
/* it has been re-acked in this SACK */
tp1->sent = SCTP_DATAGRAM_ACKED;
@@ -4382,8 +4420,11 @@ again:
stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_24;
sctp_abort_an_association(stcb->sctp_ep, stcb, SCTP_RESPONSE_TO_USER_REQ, oper);
} else {
+ if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) ||
+ (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
+ SCTP_STAT_DECR_GAUGE32(sctps_currestab);
+ }
asoc->state = SCTP_STATE_SHUTDOWN_SENT;
- SCTP_STAT_DECR_GAUGE32(sctps_currestab);
sctp_stop_timers_for_shutdown(stcb);
sctp_send_shutdown(stcb,
stcb->asoc.primary_destination);
@@ -4397,8 +4438,8 @@ again:
if (asoc->state & SCTP_STATE_PARTIAL_MSG_LEFT) {
goto abort_out_now;
}
- asoc->state = SCTP_STATE_SHUTDOWN_ACK_SENT;
SCTP_STAT_DECR_GAUGE32(sctps_currestab);
+ asoc->state = SCTP_STATE_SHUTDOWN_ACK_SENT;
sctp_send_shutdown_ack(stcb,
stcb->asoc.primary_destination);
@@ -4896,17 +4937,7 @@ done_with_it:
* we had some before and now we have NONE.
*/
- if (sctp_cmt_on_off) {
- /*
- * Don't check for revoked if CMT is ON. CMT causes
- * reordering of data and acks (received on different
- * interfaces) can be persistently reordered. Acking
- * followed by apparent revoking and re-acking causes
- * unexpected weird behavior. So, at this time, CMT does not
- * respect renegs. Renegs will have to be recovered through
- * a timeout. Not a big deal for such a rare event.
- */
- } else if (num_seg)
+ if (num_seg)
sctp_check_for_revoked(asoc, cum_ack, biggest_tsn_acked);
else if (asoc->saw_sack_with_frags) {
int cnt_revoked = 0;
@@ -5020,8 +5051,11 @@ done_with_it:
sctp_abort_an_association(stcb->sctp_ep, stcb, SCTP_RESPONSE_TO_USER_REQ, oper);
return;
} else {
+ if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) ||
+ (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
+ SCTP_STAT_DECR_GAUGE32(sctps_currestab);
+ }
asoc->state = SCTP_STATE_SHUTDOWN_SENT;
- SCTP_STAT_DECR_GAUGE32(sctps_currestab);
sctp_stop_timers_for_shutdown(stcb);
sctp_send_shutdown(stcb,
stcb->asoc.primary_destination);
@@ -5036,8 +5070,8 @@ done_with_it:
if (asoc->state & SCTP_STATE_PARTIAL_MSG_LEFT) {
goto abort_out_now;
}
- asoc->state = SCTP_STATE_SHUTDOWN_ACK_SENT;
SCTP_STAT_DECR_GAUGE32(sctps_currestab);
+ asoc->state = SCTP_STATE_SHUTDOWN_ACK_SENT;
sctp_send_shutdown_ack(stcb,
stcb->asoc.primary_destination);
diff --git a/sys/netinet/sctp_input.c b/sys/netinet/sctp_input.c
index 0a6fdea..f227c8e 100644
--- a/sys/netinet/sctp_input.c
+++ b/sys/netinet/sctp_input.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2001-2006, Cisco Systems, Inc. All rights reserved.
+ * Copyright (c) 2001-2007, Cisco Systems, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -52,7 +52,6 @@ extern uint32_t sctp_debug_on;
-
struct sctp_foo_stuff sctp_logoff[30000];
int sctp_logoff_stuff = 0;
@@ -612,7 +611,8 @@ sctp_handle_shutdown(struct sctp_shutdown_chunk *cp,
/* send SHUTDOWN-ACK */
sctp_send_shutdown_ack(stcb, stcb->asoc.primary_destination);
/* move to SHUTDOWN-ACK-SENT state */
- if (asoc->state == SCTP_STATE_SHUTDOWN_RECEIVED) {
+ if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) ||
+ (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
SCTP_STAT_DECR_GAUGE32(sctps_currestab);
}
asoc->state = SCTP_STATE_SHUTDOWN_ACK_SENT;
@@ -1057,7 +1057,7 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset,
/* I know that the TCB is non-NULL from the caller */
asoc = &stcb->asoc;
- for (how_indx = 0; how_indx < sizeof(asoc->cookie_how); i++) {
+ for (how_indx = 0; how_indx < sizeof(asoc->cookie_how); how_indx++) {
if (asoc->cookie_how[how_indx] == 0)
break;
}
@@ -1160,16 +1160,20 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset,
net, SCTP_FROM_SCTP_INPUT + SCTP_LOC_11);
sctp_timer_stop(SCTP_TIMER_TYPE_INIT, inp, stcb, net, SCTP_FROM_SCTP_INPUT + SCTP_LOC_12);
/* update current state */
+ if (SCTP_GET_STATE(asoc) == SCTP_STATE_COOKIE_ECHOED)
+ SCTP_STAT_INCR_COUNTER32(sctps_activeestab);
+ else
+ SCTP_STAT_INCR_COUNTER32(sctps_collisionestab);
if (asoc->state & SCTP_STATE_SHUTDOWN_PENDING) {
- asoc->state = SCTP_STATE_OPEN |
- SCTP_STATE_SHUTDOWN_PENDING;
+ asoc->state = SCTP_STATE_OPEN | SCTP_STATE_SHUTDOWN_PENDING;
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD,
stcb->sctp_ep, stcb, asoc->primary_destination);
- } else if ((asoc->state & SCTP_STATE_SHUTDOWN_SENT) == 0) {
+ } else {
/* if ok, move to OPEN state */
asoc->state = SCTP_STATE_OPEN;
}
+ SCTP_STAT_INCR_GAUGE32(sctps_currestab);
sctp_stop_all_cookie_timers(stcb);
if (((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
(stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) &&
@@ -1204,6 +1208,7 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset,
* we're in the OPEN state (or beyond), so peer must
* have simply lost the COOKIE-ACK
*/
+
break;
} /* end switch */
sctp_stop_all_cookie_timers(stcb);
@@ -1331,10 +1336,19 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset,
SCTP_PCB_FLAGS_CONNECTED;
soisconnected(stcb->sctp_ep->sctp_socket);
}
+ if (SCTP_GET_STATE(asoc) == SCTP_STATE_COOKIE_ECHOED)
+ SCTP_STAT_INCR_COUNTER32(sctps_activeestab);
+ else
+ SCTP_STAT_INCR_COUNTER32(sctps_collisionestab);
+ SCTP_STAT_INCR_COUNTER32(sctps_activeestab);
+ SCTP_STAT_INCR_GAUGE32(sctps_currestab);
+ } else if (SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) {
+ SCTP_STAT_INCR_COUNTER32(sctps_restartestab);
+ } else {
+ SCTP_STAT_INCR_COUNTER32(sctps_collisionestab);
}
if (asoc->state & SCTP_STATE_SHUTDOWN_PENDING) {
- asoc->state = SCTP_STATE_OPEN |
- SCTP_STATE_SHUTDOWN_PENDING;
+ asoc->state = SCTP_STATE_OPEN | SCTP_STATE_SHUTDOWN_PENDING;
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD,
stcb->sctp_ep, stcb, asoc->primary_destination);
@@ -1379,6 +1393,16 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset,
/* notify upper layer */
*notification = SCTP_NOTIFY_ASSOC_RESTART;
atomic_add_int(&stcb->asoc.refcnt, 1);
+ if ((SCTP_GET_STATE(asoc) != SCTP_STATE_OPEN) &&
+ (SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_RECEIVED) &&
+ (SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_SENT)) {
+ SCTP_STAT_INCR_GAUGE32(sctps_currestab);
+ }
+ if (SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) {
+ SCTP_STAT_INCR_GAUGE32(sctps_restartestab);
+ } else if (SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_SENT) {
+ SCTP_STAT_INCR_GAUGE32(sctps_collisionestab);
+ }
if (asoc->state & SCTP_STATE_SHUTDOWN_PENDING) {
asoc->state = SCTP_STATE_OPEN |
SCTP_STATE_SHUTDOWN_PENDING;
@@ -1509,7 +1533,7 @@ sctp_process_cookie_new(struct mbuf *m, int iphlen, int offset,
int retval;
int error = 0;
uint32_t old_tag;
- uint8_t chunk_buf[DEFAULT_CHUNK_BUFFER];
+ uint8_t auth_chunk_buf[SCTP_PARAM_BUFFER_SIZE];
/*
* find and validate the INIT chunk in the cookie (peer's info) the
@@ -1647,7 +1671,7 @@ sctp_process_cookie_new(struct mbuf *m, int iphlen, int offset,
struct sctp_auth_chunk *auth;
auth = (struct sctp_auth_chunk *)
- sctp_m_getptr(m, auth_offset, auth_len, chunk_buf);
+ sctp_m_getptr(m, auth_offset, auth_len, auth_chunk_buf);
if (sctp_handle_auth(stcb, auth, m, auth_offset)) {
/* auth HMAC failed, dump the assoc and packet */
#ifdef SCTP_DEBUG
@@ -1812,7 +1836,6 @@ sctp_handle_cookie_echo(struct mbuf *m, int iphlen, int offset,
sin->sin_port = sh->dest_port;
sin->sin_addr.s_addr = iph->ip_dst.s_addr;
size_of_pkt = SCTP_GET_IPV4_LENGTH(iph);
-
} else if (iph->ip_v == (IPV6_VERSION >> 4)) {
/* its IPv6 */
struct ip6_hdr *ip6;
@@ -1825,7 +1848,7 @@ sctp_handle_cookie_echo(struct mbuf *m, int iphlen, int offset,
ip6 = mtod(m, struct ip6_hdr *);
sin6->sin6_port = sh->dest_port;
sin6->sin6_addr = ip6->ip6_dst;
- size_of_pkt = SCTP_GET_IPV6_LENGTH(ip6);
+ size_of_pkt = SCTP_GET_IPV6_LENGTH(ip6) + iphlen;
} else {
return (NULL);
}
@@ -2796,13 +2819,13 @@ static void
sctp_clean_up_stream_reset(struct sctp_tcb *stcb)
{
struct sctp_association *asoc;
-
- asoc = &stcb->asoc;
struct sctp_tmit_chunk *chk = stcb->asoc.str_reset;
if (stcb->asoc.str_reset == NULL) {
return;
}
+ asoc = &stcb->asoc;
+
sctp_timer_stop(SCTP_TIMER_TYPE_STRRESET, stcb->sctp_ep, stcb, chk->whoTo, SCTP_FROM_SCTP_INPUT + SCTP_LOC_25);
TAILQ_REMOVE(&asoc->control_send_queue,
chk,
@@ -3104,11 +3127,11 @@ sctp_handle_stream_reset(struct sctp_tcb *stcb, struct sctp_stream_reset_out_req
struct sctp_tmit_chunk *chk;
struct sctp_chunkhdr *ch;
struct sctp_paramhdr *ph;
+ int ret_code = 0;
+ int num_param = 0;
/* now it may be a reset or a reset-response */
chk_length = ntohs(sr_req->ch.chunk_length);
- int ret_code = 0;
- int num_param = 0;
/* setup for adding the response */
sctp_alloc_a_chunk(stcb, chk);
@@ -3144,7 +3167,6 @@ strres_nochunk:
ch->chunk_length = htons(chk->send_size);
SCTP_BUF_LEN(chk->data) = SCTP_SIZE32(chk->send_size);
-
ph = (struct sctp_paramhdr *)&sr_req->sr_req;
while ((size_t)chk_length >= sizeof(struct sctp_stream_reset_tsn_request)) {
param_len = ntohs(ph->param_length);
@@ -3504,7 +3526,7 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length,
* d-mtu-ceiling for now (2k) and that should hopefully work ...
* until we get into jumbo grams and such..
*/
- uint8_t chunk_buf[DEFAULT_CHUNK_BUFFER];
+ uint8_t chunk_buf[SCTP_CHUNK_BUFFER_SIZE];
struct sctp_tcb *locked_tcb = stcb;
int got_auth = 0;
uint32_t auth_offset = 0, auth_len = 0;
diff --git a/sys/netinet/sctp_os.h b/sys/netinet/sctp_os.h
index aacf877..15d256e 100644
--- a/sys/netinet/sctp_os.h
+++ b/sys/netinet/sctp_os.h
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2006, Cisco Systems, Inc. All rights reserved.
+ * Copyright (c) 2006-2007, Cisco Systems, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -47,10 +47,11 @@ __FBSDID("$FreeBSD$");
* name = string name of the zone/pool.
* size = size of each zone/pool element.
* number = number of elements in zone/pool.
+ * type = structure type to allocate
*
* sctp_zone_t
* SCTP_ZONE_INIT(zone, name, size, number)
- * SCTP_ZONE_GET(zone)
+ * SCTP_ZONE_GET(zone, type)
* SCTP_ZONE_FREE(zone, element)
* SCTP_ZONE_DESTROY(zone)
*/
diff --git a/sys/netinet/sctp_os_bsd.h b/sys/netinet/sctp_os_bsd.h
index eb2993e..c95b698 100644
--- a/sys/netinet/sctp_os_bsd.h
+++ b/sys/netinet/sctp_os_bsd.h
@@ -91,6 +91,8 @@ __FBSDID("$FreeBSD$");
#include <netinet6/scope6_var.h>
#endif /* INET6 */
+
+
#include <netinet/ip_options.h>
@@ -104,6 +106,7 @@ __FBSDID("$FreeBSD$");
*
*/
#define USER_ADDR_NULL (NULL) /* FIX ME: temp */
+#define SCTP_LIST_EMPTY(list) LIST_EMPTY(list)
/*
* general memory allocation
@@ -137,8 +140,8 @@ typedef struct uma_zone *sctp_zone_t;
}
/* SCTP_ZONE_GET: allocate element from the zone */
-#define SCTP_ZONE_GET(zone) \
- uma_zalloc(zone, M_NOWAIT);
+#define SCTP_ZONE_GET(zone, type) \
+ (type *)uma_zalloc(zone, M_NOWAIT);
/* SCTP_ZONE_FREE: free element from the zone */
#define SCTP_ZONE_FREE(zone, element) \
@@ -165,7 +168,6 @@ typedef struct callout sctp_os_timer_t;
/*
* Functions
*/
-#define SCTP_READ_RANDOM(buf, len) read_random(buf, len)
/* Mbuf manipulation and access macros */
#define SCTP_BUF_LEN(m) (m->m_len)
@@ -224,4 +226,31 @@ typedef struct callout sctp_os_timer_t;
#define SCTP_IPV6_V6ONLY(inp) (((struct inpcb *)inp)->inp_flags & IN6P_IPV6_V6ONLY)
+/*
+ * SCTP AUTH
+ */
+#define HAVE_SHA2
+
+#define SCTP_READ_RANDOM(buf, len) read_random(buf, len)
+
+#ifdef USE_SCTP_SHA1
+#include <netinet/sctp_sha1.h>
+#else
+#include <crypto/sha1.h>
+/* map standard crypto API names */
+#define SHA1_Init SHA1Init
+#define SHA1_Update SHA1Update
+#define SHA1_Final(x,y) SHA1Final((caddr_t)x, y)
+#endif
+
+#if defined(HAVE_SHA2)
+#include <crypto/sha2/sha2.h>
+#endif
+
+#include <sys/md5.h>
+/* map standard crypto API names */
+#define MD5_Init MD5Init
+#define MD5_Update MD5Update
+#define MD5_Final MD5Final
+
#endif
diff --git a/sys/netinet/sctp_output.c b/sys/netinet/sctp_output.c
index d1ceb6b..7572130 100644
--- a/sys/netinet/sctp_output.c
+++ b/sys/netinet/sctp_output.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2001-2006, Cisco Systems, Inc. All rights reserved.
+ * Copyright (c) 2001-2007, Cisco Systems, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -2372,7 +2372,6 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
struct ip6_hdr *ip6h;
struct route_in6 ip6route;
-
struct ifnet *ifp;
u_char flowTop;
uint16_t flowBottom;
@@ -2783,11 +2782,17 @@ sctp_send_initiate(struct sctp_inpcb *inp, struct sctp_tcb *stcb)
/* attach RANDOM parameter, if available */
if (stcb->asoc.authinfo.random != NULL) {
random = (struct sctp_auth_random *)(mtod(m, caddr_t)+SCTP_BUF_LEN(m));
- random->ph.param_type = htons(SCTP_RANDOM);
p_len = sizeof(*random) + stcb->asoc.authinfo.random_len;
+#ifdef SCTP_AUTH_DRAFT_04
+ random->ph.param_type = htons(SCTP_RANDOM);
random->ph.param_length = htons(p_len);
- bcopy(stcb->asoc.authinfo.random->key, random->random_data,
+ bcopy(stcb->asoc.authinfo.random->key,
+ random->random_data,
stcb->asoc.authinfo.random_len);
+#else
+ /* random key already contains the header */
+ bcopy(stcb->asoc.authinfo.random->key, random, p_len);
+#endif
/* zero out any padding required */
bzero((caddr_t)random + p_len, SCTP_SIZE32(p_len) - p_len);
SCTP_BUF_LEN(m) += SCTP_SIZE32(p_len);
@@ -2900,7 +2905,7 @@ sctp_arethere_unrecognized_parameters(struct mbuf *in_initpkt,
struct sctp_paramhdr *phdr, params;
struct mbuf *mat, *op_err;
- char tempbuf[2048];
+ char tempbuf[SCTP_CHUNK_BUFFER_SIZE];
int at, limit, pad_needed;
uint16_t ptype, plen;
int err_at;
@@ -4101,7 +4106,7 @@ sctp_msg_append(struct sctp_tcb *stcb,
error = ECONNRESET;
goto out_now;
}
- sp = (struct sctp_stream_queue_pending *)SCTP_ZONE_GET(sctppcbinfo.ipi_zone_strmoq);
+ sp = SCTP_ZONE_GET(sctppcbinfo.ipi_zone_strmoq, struct sctp_stream_queue_pending);
if (sp == NULL) {
error = ENOMEM;
goto out_now;
@@ -4411,8 +4416,10 @@ sctp_sendall_iterator(struct sctp_inpcb *inp, struct sctp_tcb *stcb, void *ptr,
* through
*/
sctp_send_shutdown(stcb, stcb->asoc.primary_destination);
+ if (SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) {
+ SCTP_STAT_DECR_GAUGE32(sctps_currestab);
+ }
asoc->state = SCTP_STATE_SHUTDOWN_SENT;
- SCTP_STAT_DECR_GAUGE32(sctps_currestab);
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN, stcb->sctp_ep, stcb,
asoc->primary_destination);
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, stcb->sctp_ep, stcb,
@@ -5089,6 +5096,17 @@ out_gu:
* Put the rest of the things in place now. Size was done earlier in
* previous loop prior to padding.
*/
+
+#ifdef SCTP_ASOCLOG_OF_TSNS
+ asoc->out_tsnlog[asoc->tsn_out_at].tsn = chk->rec.data.TSN_seq;
+ asoc->out_tsnlog[asoc->tsn_out_at].strm = chk->rec.data.stream_number;
+ asoc->out_tsnlog[asoc->tsn_out_at].seq = chk->rec.data.stream_seq;
+ asoc->tsn_out_at++;
+ if (asoc->tsn_out_at >= SCTP_TSN_LOG_SIZE) {
+ asoc->tsn_out_at = 0;
+ }
+#endif
+
dchkh->ch.chunk_type = SCTP_DATA;
dchkh->ch.chunk_flags = chk->rec.data.rcv_flags;
dchkh->dp.tsn = htonl(chk->rec.data.TSN_seq);
@@ -5350,15 +5368,14 @@ sctp_med_chunk_output(struct sctp_inpcb *inp,
int asconf, cookie, no_out_cnt;
int bundle_at, ctl_cnt, no_data_chunks, cwnd_full_ind, eeor_mode;
unsigned int mtu, r_mtu, omtu, mx_mtu, to_out;
-
- *num_out = 0;
struct sctp_nets *start_at, *old_startat = NULL, *send_start_at;
-
- cwnd_full_ind = 0;
int tsns_sent = 0;
uint32_t auth_offset = 0;
struct sctp_auth_chunk *auth = NULL;
+ *num_out = 0;
+ cwnd_full_ind = 0;
+
if ((asoc->state & SCTP_STATE_SHUTDOWN_PENDING) ||
(asoc->state & SCTP_STATE_SHUTDOWN_RECEIVED) ||
(sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXPLICIT_EOR))) {
@@ -7596,7 +7613,13 @@ sctp_send_sack(struct sctp_tcb *stcb)
sack = mtod(a_chk->data, struct sctp_sack_chunk *);
sack->ch.chunk_type = SCTP_SELECTIVE_ACK;
/* 0x01 is used by nonce for ecn */
- sack->ch.chunk_flags = (asoc->receiver_nonce_sum & SCTP_SACK_NONCE_SUM);
+ if ((sctp_ecn_enable) &&
+ (sctp_ecn_nonce) &&
+ (asoc->peer_supports_ecn_nonce))
+ sack->ch.chunk_flags = (asoc->receiver_nonce_sum & SCTP_SACK_NONCE_SUM);
+ else
+ sack->ch.chunk_flags = 0;
+
if (sctp_cmt_on_off && sctp_cmt_use_dac) {
/*
* CMT DAC algorithm: If 2 (i.e., 0x10) packets have been
@@ -7929,7 +7952,6 @@ sctp_send_shutdown_complete2(struct mbuf *m, int iphlen, struct sctphdr *sh)
} else if (ip6_out != NULL) {
struct route_in6 ro;
-
bzero(&ro, sizeof(ro));
ip6_output(o_pak, NULL, &ro, 0, NULL, NULL
,NULL
@@ -8789,7 +8811,6 @@ sctp_send_abort(struct mbuf *m, int iphlen, struct sctphdr *sh, uint32_t vtag,
} else if (ip6_out != NULL) {
struct route_in6 ro;
-
/* zap the stack pointer to the route */
bzero(&ro, sizeof(ro));
#ifdef SCTP_DEBUG
@@ -8907,7 +8928,6 @@ sctp_send_operr_to(struct mbuf *m, int iphlen,
} else {
/* V6 */
struct route_in6 ro;
-
struct ip6_hdr *out6, *in6;
o_pak = SCTP_GET_HEADER_FOR_OUTPUT(sizeof(struct ip6_hdr));
@@ -9114,7 +9134,7 @@ sctp_copy_it_in(struct sctp_tcb *stcb,
*errno = ECONNRESET;
goto out_now;
}
- sp = (struct sctp_stream_queue_pending *)SCTP_ZONE_GET(sctppcbinfo.ipi_zone_strmoq);
+ sp = SCTP_ZONE_GET(sctppcbinfo.ipi_zone_strmoq, struct sctp_stream_queue_pending);
if (sp == NULL) {
*errno = ENOMEM;
goto out_now;
@@ -10096,8 +10116,10 @@ dataless_eof:
(SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_ACK_SENT)) {
/* only send SHUTDOWN the first time through */
sctp_send_shutdown(stcb, stcb->asoc.primary_destination);
+ if (SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) {
+ SCTP_STAT_DECR_GAUGE32(sctps_currestab);
+ }
asoc->state = SCTP_STATE_SHUTDOWN_SENT;
- SCTP_STAT_DECR_GAUGE32(sctps_currestab);
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN, stcb->sctp_ep, stcb,
asoc->primary_destination);
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, stcb->sctp_ep, stcb,
diff --git a/sys/netinet/sctp_pcb.c b/sys/netinet/sctp_pcb.c
index f089616..e68c2b8 100644
--- a/sys/netinet/sctp_pcb.c
+++ b/sys/netinet/sctp_pcb.c
@@ -1326,7 +1326,7 @@ sctp_inpcb_alloc(struct socket *so)
error = 0;
SCTP_INP_INFO_WLOCK();
- inp = (struct sctp_inpcb *)SCTP_ZONE_GET(sctppcbinfo.ipi_zone_ep);
+ inp = SCTP_ZONE_GET(sctppcbinfo.ipi_zone_ep, struct sctp_inpcb);
if (inp == NULL) {
printf("Out of SCTP-INPCB structures - no resources\n");
SCTP_INP_INFO_WUNLOCK();
@@ -1504,7 +1504,6 @@ sctp_move_pcb_and_assoc(struct sctp_inpcb *old_inp, struct sctp_inpcb *new_inp,
SCTP_INP_WLOCK(new_inp);
SCTP_TCB_LOCK(stcb);
-
new_inp->sctp_ep.time_of_secret_change =
old_inp->sctp_ep.time_of_secret_change;
memcpy(new_inp->sctp_ep.secret_key, old_inp->sctp_ep.secret_key,
@@ -1556,8 +1555,7 @@ sctp_move_pcb_and_assoc(struct sctp_inpcb *old_inp, struct sctp_inpcb *new_inp,
if ((new_inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) == 0) {
/* Subset bound, so copy in the laddr list from the old_inp */
LIST_FOREACH(oladdr, &old_inp->sctp_addr_list, sctp_nxt_addr) {
- laddr = (struct sctp_laddr *)SCTP_ZONE_GET(
- sctppcbinfo.ipi_zone_laddr);
+ laddr = SCTP_ZONE_GET(sctppcbinfo.ipi_zone_laddr, struct sctp_laddr);
if (laddr == NULL) {
/*
* Gak, what can we do? This assoc is really
@@ -2145,8 +2143,11 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from)
* so I send shutdown
*/
sctp_send_shutdown(asoc, asoc->asoc.primary_destination);
+ if ((SCTP_GET_STATE(&asoc->asoc) == SCTP_STATE_OPEN) ||
+ (SCTP_GET_STATE(&asoc->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
+ SCTP_STAT_DECR_GAUGE32(sctps_currestab);
+ }
asoc->asoc.state = SCTP_STATE_SHUTDOWN_SENT;
- SCTP_STAT_DECR_GAUGE32(sctps_currestab);
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN, asoc->sctp_ep, asoc,
asoc->asoc.primary_destination);
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, asoc->sctp_ep, asoc,
@@ -2636,12 +2637,13 @@ sctp_add_remote_addr(struct sctp_tcb *stcb, struct sockaddr *newaddr,
/* not supported family type */
return (-1);
}
- net = (struct sctp_nets *)SCTP_ZONE_GET(sctppcbinfo.ipi_zone_net);
+ net = SCTP_ZONE_GET(sctppcbinfo.ipi_zone_net, struct sctp_nets);
if (net == NULL) {
return (-1);
}
SCTP_INCR_RADDR_COUNT();
bzero(net, sizeof(*net));
+ SCTP_GETTIME_TIMEVAL(&net->start_time);
memcpy(&net->ro._l_addr, newaddr, newaddr->sa_len);
if (newaddr->sa_family == AF_INET) {
((struct sockaddr_in *)&net->ro._l_addr)->sin_port = stcb->rport;
@@ -2903,7 +2905,7 @@ sctp_aloc_assoc(struct sctp_inpcb *inp, struct sockaddr *firstaddr,
return (NULL);
}
}
- stcb = (struct sctp_tcb *)SCTP_ZONE_GET(sctppcbinfo.ipi_zone_asoc);
+ stcb = SCTP_ZONE_GET(sctppcbinfo.ipi_zone_asoc, struct sctp_tcb);
if (stcb == NULL) {
/* out of memory? */
*error = ENOMEM;
@@ -3076,7 +3078,7 @@ sctp_add_vtag_to_timewait(struct sctp_inpcb *inp, uint32_t tag, uint32_t time)
SCTP_GETTIME_TIMEVAL(&now);
chain = &sctppcbinfo.vtag_timewait[(tag % SCTP_STACK_VTAG_HASH_SIZE)];
set = 0;
- if (!LIST_EMPTY(chain)) {
+ if (!SCTP_LIST_EMPTY(chain)) {
/* Block(s) present, lets find space, and expire on the fly */
LIST_FOREACH(twait_block, chain, sctp_nxt_tagblock) {
for (i = 0; i < SCTP_NUMBER_IN_VTAG_BLOCK; i++) {
@@ -3630,7 +3632,7 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre
}
/* local addresses, if any */
- while (!LIST_EMPTY(&asoc->sctp_local_addr_list)) {
+ while (!SCTP_LIST_EMPTY(&asoc->sctp_local_addr_list)) {
laddr = LIST_FIRST(&asoc->sctp_local_addr_list);
LIST_REMOVE(laddr, sctp_nxt_addr);
SCTP_ZONE_FREE(sctppcbinfo.ipi_zone_laddr, laddr);
@@ -3993,7 +3995,7 @@ sctp_insert_laddr(struct sctpladdr *list, struct ifaddr *ifa)
{
struct sctp_laddr *laddr;
- laddr = (struct sctp_laddr *)SCTP_ZONE_GET(sctppcbinfo.ipi_zone_laddr);
+ laddr = SCTP_ZONE_GET(sctppcbinfo.ipi_zone_laddr, struct sctp_laddr);
if (laddr == NULL) {
/* out of memory? */
return (EINVAL);
@@ -4152,7 +4154,7 @@ sctp_pcb_init()
sctp_pcb_initialized = 1;
bzero(&sctpstat, sizeof(struct sctpstat));
-
+ SCTP_GETTIME_TIMEVAL(&sctpstat.sctps_discontinuitytime);
/* init the empty list of (All) Endpoints */
LIST_INIT(&sctppcbinfo.listhead);
@@ -4268,11 +4270,13 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m,
struct sockaddr *local_sa = (struct sockaddr *)&dest_store;
struct sockaddr_in sin;
struct sockaddr_in6 sin6;
- uint8_t store[384];
+ uint8_t random_store[SCTP_PARAM_BUFFER_SIZE];
struct sctp_auth_random *random = NULL;
uint16_t random_len = 0;
+ uint8_t hmacs_store[SCTP_PARAM_BUFFER_SIZE];
struct sctp_auth_hmac_algo *hmacs = NULL;
uint16_t hmacs_len = 0;
+ uint8_t chunks_store[SCTP_PARAM_BUFFER_SIZE];
struct sctp_auth_chunk_list *chunks = NULL;
uint16_t num_chunks = 0;
sctp_key_t *new_key;
@@ -4569,7 +4573,7 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m,
} else if (ptype == SCTP_SUPPORTED_CHUNK_EXT) {
/* A supported extension chunk */
struct sctp_supported_chunk_types_param *pr_supported;
- uint8_t local_store[128];
+ uint8_t local_store[SCTP_PARAM_BUFFER_SIZE];
int num_ent, i;
phdr = sctp_get_next_param(m, offset,
@@ -4613,14 +4617,14 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m,
stcb->asoc.peer_supports_ecn_nonce = 1;
stcb->asoc.ecn_nonce_allowed = 1;
} else if (ptype == SCTP_RANDOM) {
- if (plen > sizeof(store))
+ if (plen > sizeof(random_store))
break;
if (got_random) {
/* already processed a RANDOM */
goto next_param;
}
phdr = sctp_get_next_param(m, offset,
- (struct sctp_paramhdr *)store,
+ (struct sctp_paramhdr *)random_store,
plen);
if (phdr == NULL)
return (-26);
@@ -4639,14 +4643,14 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m,
int num_hmacs;
int i;
- if (plen > sizeof(store))
+ if (plen > sizeof(hmacs_store))
break;
if (got_hmacs) {
/* already processed a HMAC list */
goto next_param;
}
phdr = sctp_get_next_param(m, offset,
- (struct sctp_paramhdr *)store,
+ (struct sctp_paramhdr *)hmacs_store,
plen);
if (phdr == NULL)
return (-28);
@@ -4670,14 +4674,14 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m,
} else if (ptype == SCTP_CHUNK_LIST) {
int i;
- if (plen > sizeof(store))
+ if (plen > sizeof(chunks_store))
break;
if (got_chklist) {
/* already processed a Chunks list */
goto next_param;
}
phdr = sctp_get_next_param(m, offset,
- (struct sctp_paramhdr *)store,
+ (struct sctp_paramhdr *)chunks_store,
plen);
if (phdr == NULL)
return (-30);
@@ -4749,21 +4753,38 @@ next_param:
return (-31);
}
/* concatenate the full random key */
- keylen = random_len + num_chunks + hmacs_len;
+#ifdef SCTP_AUTH_DRAFT_04
+ keylen = random_len;
new_key = sctp_alloc_key(keylen);
if (new_key != NULL) {
/* copy in the RANDOM */
if (random != NULL)
bcopy(random->random_data, new_key->key, random_len);
+ }
+#else
+ keylen = sizeof(*random) + random_len + sizeof(*chunks) + num_chunks +
+ sizeof(*hmacs) + hmacs_len;
+ new_key = sctp_alloc_key(keylen);
+ if (new_key != NULL) {
+ /* copy in the RANDOM */
+ if (random != NULL) {
+ keylen = sizeof(*random) + random_len;
+ bcopy(random, new_key->key, keylen);
+ }
/* append in the AUTH chunks */
- if (chunks != NULL)
- bcopy(chunks->chunk_types, new_key->key + random_len,
- num_chunks);
+ if (chunks != NULL) {
+ bcopy(chunks, new_key->key + keylen,
+ sizeof(*chunks) + num_chunks);
+ keylen += sizeof(*chunks) + num_chunks;
+ }
/* append in the HMACs */
- if (hmacs != NULL)
- bcopy(hmacs->hmac_ids, new_key->key + random_len + num_chunks,
- hmacs_len);
- } else {
+ if (hmacs != NULL) {
+ bcopy(hmacs, new_key->key + keylen,
+ sizeof(*hmacs) + hmacs_len);
+ }
+ }
+#endif
+ else {
return (-32);
}
if (stcb->asoc.authinfo.peer_random != NULL)
@@ -4871,7 +4892,7 @@ check_restart:
}
check_time_wait:
/* Now what about timed wait ? */
- if (!LIST_EMPTY(chain)) {
+ if (!SCTP_LIST_EMPTY(chain)) {
/*
* Block(s) are present, lets see if we have this tag in the
* list
diff --git a/sys/netinet/sctp_peeloff.c b/sys/netinet/sctp_peeloff.c
index d621947..88da761 100644
--- a/sys/netinet/sctp_peeloff.c
+++ b/sys/netinet/sctp_peeloff.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2001-2006, Cisco Systems, Inc. All rights reserved.
+ * Copyright (c) 2001-2007, Cisco Systems, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
diff --git a/sys/netinet/sctp_structs.h b/sys/netinet/sctp_structs.h
index d96e7d8..412ee02 100644
--- a/sys/netinet/sctp_structs.h
+++ b/sys/netinet/sctp_structs.h
@@ -263,6 +263,10 @@ struct sctp_nets {
#ifdef SCTP_HIGH_SPEED
uint8_t last_hs_used; /* index into the last HS table entry we used */
#endif
+ struct timeval start_time; /* time when this net was created */
+ uint32_t marked_retrans;/* number or DATA chunks marked for timer
+ * based retransmissions */
+ uint32_t marked_fastretrans;
};
@@ -444,6 +448,14 @@ struct sctp_scoping {
uint8_t site_scope;
};
+#define SCTP_TSN_LOG_SIZE 40
+
+struct sctp_tsn_log {
+ uint32_t tsn;
+ uint16_t strm;
+ uint16_t seq;
+};
+
/*
* Here we have information about each individual association that we track.
* We probably in production would be more dynamic. But for ease of
@@ -647,6 +659,16 @@ struct sctp_association {
uint32_t last_reset_action[SCTP_MAX_RESET_PARAMS];
uint32_t last_sending_seq[SCTP_MAX_RESET_PARAMS];
uint32_t last_base_tsnsent[SCTP_MAX_RESET_PARAMS];
+#ifdef SCTP_ASOCLOG_OF_TSNS
+ /*
+ * special log - This adds considerable size to the asoc, but
+ * provides a log that you can use to detect problems via kgdb.
+ */
+ struct sctp_tsn_log in_tsnlog[SCTP_TSN_LOG_SIZE];
+ struct sctp_tsn_log out_tsnlog[SCTP_TSN_LOG_SIZE];
+ uint16_t tsn_in_at;
+ uint16_t tsn_out_at;
+#endif /* SCTP_ASOCLOG_OF_TSNS */
/*
* window state information and smallest MTU that I use to bound
* segmentation
@@ -881,6 +903,16 @@ struct sctp_association {
* trailing locactions out. If I get a TSN above the array
* mappingArraySz, I discard the datagram and let retransmit happen.
*/
+ uint32_t marked_retrans;
+ uint32_t timoinit;
+ uint32_t timodata;
+ uint32_t timosack;
+ uint32_t timoshutdown;
+ uint32_t timoheartbeat;
+ uint32_t timocookie;
+ uint32_t timoshutdownack;
+ struct timeval start_time;
+ struct timeval discontinuity_time;
};
#endif
diff --git a/sys/netinet/sctp_timer.c b/sys/netinet/sctp_timer.c
index d065dbe..62de925 100644
--- a/sys/netinet/sctp_timer.c
+++ b/sys/netinet/sctp_timer.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2001-2006, Cisco Systems, Inc. All rights reserved.
+ * Copyright (c) 2001-2007, Cisco Systems, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -637,6 +637,8 @@ sctp_mark_all_for_resend(struct sctp_tcb *stcb,
stcb->asoc.total_flight_count--;
chk->sent = SCTP_DATAGRAM_RESEND;
SCTP_STAT_INCR(sctps_markedretrans);
+ net->marked_retrans++;
+ stcb->asoc.marked_retrans++;
#ifdef SCTP_FLIGHT_LOGGING
sctp_misc_ints(SCTP_FLIGHT_LOG_DOWN,
chk->whoTo->flight_size,
@@ -1558,12 +1560,14 @@ sctp_autoclose_timer(struct sctp_inpcb *inp,
* there is nothing queued to send, so I'm
* done...
*/
- if (SCTP_GET_STATE(asoc) !=
- SCTP_STATE_SHUTDOWN_SENT) {
+ if (SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_SENT) {
/* only send SHUTDOWN 1st time thru */
sctp_send_shutdown(stcb, stcb->asoc.primary_destination);
+ if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) ||
+ (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
+ SCTP_STAT_DECR_GAUGE32(sctps_currestab);
+ }
asoc->state = SCTP_STATE_SHUTDOWN_SENT;
- SCTP_STAT_DECR_GAUGE32(sctps_currestab);
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN,
stcb->sctp_ep, stcb,
asoc->primary_destination);
@@ -1590,7 +1594,6 @@ sctp_autoclose_timer(struct sctp_inpcb *inp,
}
}
-
void
sctp_iterator_timer(struct sctp_iterator *it)
{
diff --git a/sys/netinet/sctp_uio.h b/sys/netinet/sctp_uio.h
index 342f02f..89a81cc 100644
--- a/sys/netinet/sctp_uio.h
+++ b/sys/netinet/sctp_uio.h
@@ -43,6 +43,7 @@ __FBSDID("$FreeBSD$");
#endif
#include <sys/types.h>
#include <sys/socket.h>
+#include <sys/time.h>
#include <netinet/in.h>
typedef uint32_t sctp_assoc_t;
@@ -83,7 +84,14 @@ struct sctp_initmsg {
* when enabled which is 48 bytes.
*/
+/*
+ * The assoc up needs a verfid
+ * all sendrcvinfo's need a verfid for SENDING only.
+ */
+
+
#define SCTP_ALIGN_RESV_PAD 96
+#define SCTP_ALIGN_RESV_PAD_SHORT 80
struct sctp_sndrcvinfo {
uint16_t sinfo_stream;
@@ -113,12 +121,14 @@ struct sctp_extrcvinfo {
uint32_t next_asocid;
uint32_t next_length;
uint32_t next_ppid;
+ uint8_t __reserve_pad[SCTP_ALIGN_RESV_PAD_SHORT];
};
#define SCTP_NO_NEXT_MSG 0x0000
#define SCTP_NEXT_MSG_AVAIL 0x0001
#define SCTP_NEXT_MSG_ISCOMPLETE 0x0002
#define SCTP_NEXT_MSG_IS_UNORDERED 0x0004
+#define SCTP_NEXT_MSG_IS_NOTIFICATION 0x0008
struct sctp_snd_all_completes {
uint16_t sall_stream;
@@ -734,6 +744,8 @@ struct sctpstat {
/* MIB according to RFC 3873 */
u_long sctps_currestab; /* sctpStats 1 (Gauge32) */
u_long sctps_activeestab; /* sctpStats 2 (Counter32) */
+ u_long sctps_restartestab;
+ u_long sctps_collisionestab;
u_long sctps_passiveestab; /* sctpStats 3 (Counter32) */
u_long sctps_aborted; /* sctpStats 4 (Counter32) */
u_long sctps_shutdown; /* sctpStats 5 (Counter32) */
@@ -749,7 +761,7 @@ struct sctpstat {
u_long sctps_reasmusrmsgs; /* sctpStats 15 (Counter64) */
u_long sctps_outpackets;/* sctpStats 16 (Counter64) */
u_long sctps_inpackets; /* sctpStats 17 (Counter64) */
- u_long sctps_discontinuitytime; /* sctpStats 18 (TimeStamp) */
+ struct timeval sctps_discontinuitytime; /* sctpStats 18 (TimeStamp) */
/* input statistics: */
u_long sctps_recvpackets; /* total input packets */
u_long sctps_recvdatagrams; /* total input datagrams */
@@ -901,12 +913,20 @@ struct xsctp_inpcb {
};
struct xsctp_tcb {
- uint16_t remote_port;
- uint16_t number_local_addresses;
- uint16_t number_remote_addresses;
- uint16_t number_incomming_streams;
- uint16_t number_outgoing_streams;
- uint32_t state;
+ uint16_t LocalPort; /* sctpAssocEntry 3 */
+ uint16_t RemPort; /* sctpAssocEntry 4 */
+ union sctp_sockstore RemPrimAddr; /* sctpAssocEntry 5/6 */
+ uint32_t HeartBeatInterval; /* sctpAssocEntry 7 */
+ uint32_t State; /* sctpAssocEntry 8 */
+ uint32_t InStreams; /* sctpAssocEntry 9 */
+ uint32_t OutStreams; /* sctpAssocEntry 10 */
+ uint32_t MaxRetr; /* sctpAssocEntry 11 */
+ uint32_t PrimProcess; /* sctpAssocEntry 12 */
+ uint32_t T1expireds; /* sctpAssocEntry 13 */
+ uint32_t T2expireds; /* sctpAssocEntry 14 */
+ uint32_t RtxChunks; /* sctpAssocEntry 15 */
+ struct timeval StartTime; /* sctpAssocEntry 16 */
+ struct timeval DiscontinuityTime; /* sctpAssocEntry 17 */
uint32_t total_sends;
uint32_t total_recvs;
uint32_t local_tag;
@@ -916,16 +936,28 @@ struct xsctp_tcb {
uint32_t cumulative_tsn;
uint32_t cumulative_tsn_ack;
/* add more association specific data here */
+ uint16_t number_local_addresses;
+ uint16_t number_remote_addresses;
};
struct xsctp_laddr {
- union sctp_sockstore address;
+ union sctp_sockstore LocalAddr; /* sctpAssocLocalAddrEntry 1/2 */
+ struct timeval LocalStartTime; /* sctpAssocLocalAddrEntry 3 */
/* add more local address specific data */
};
struct xsctp_raddr {
- union sctp_sockstore address;
- uint16_t state;
+ union sctp_sockstore RemAddr; /* sctpAssocLocalRemEntry 1/2 */
+ uint8_t RemAddrActive; /* sctpAssocLocalRemEntry 3 */
+ uint8_t RemAddrConfirmed; /* */
+ uint8_t RemAddrHBActive;/* sctpAssocLocalRemEntry 4 */
+ uint32_t RemAddrRTO; /* sctpAssocLocalRemEntry 5 */
+ uint32_t RemAddrMaxPathRtx; /* sctpAssocLocalRemEntry 6 */
+ uint32_t RemAddrRtx; /* sctpAssocLocalRemEntry 7 */
+ uint32_t RemAddrErrorCounter; /* */
+ uint32_t RemAddrCwnd; /* */
+ uint32_t RemAddrFlightSize; /* */
+ struct timeval RemAddrStartTime; /* sctpAssocLocalRemEntry 8 */
/* add more remote address specific data */
};
diff --git a/sys/netinet/sctp_usrreq.c b/sys/netinet/sctp_usrreq.c
index 673e13e..1e0d5b3 100644
--- a/sys/netinet/sctp_usrreq.c
+++ b/sys/netinet/sctp_usrreq.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2001-2006, Cisco Systems, Inc. All rights reserved.
+ * Copyright (c) 2001-2007, Cisco Systems, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -104,7 +104,6 @@ int sctp_chunkscale = SCTP_CHUNKQUEUE_SCALE;
unsigned int sctp_cmt_on_off = 0;
unsigned int sctp_cmt_sockopt_on_off = 0;
unsigned int sctp_cmt_use_dac = 0;
-unsigned int sctp_cmt_sockopt_use_dac = 0;
int sctp_L2_abc_variable = 1;
unsigned int sctp_early_fr = 0;
@@ -604,9 +603,9 @@ sctp_assoclist(SYSCTL_HANDLER_ARGS)
* LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr)
* { error = SYSCTL_OUT(req, &xladdr, sizeof(struct
* xsctp_laddr)); if (error) { #if
- * defined(SCTP_APPLE_FINE_GRAINED_LOCKING)
- * socket_unlock(inp->ip_inp.inp.inp_socket, 1);
- * lck_rw_unlock_shared(sctppcbinfo.ipi_ep_mtx); #endif
+ * defined(SCTP_PER_SOCKET_LOCKING)
+ * SCTP_SOCKET_UNLOCK(SCTP_INP_SO(inp), 1);
+ * SCTP_UNLOCK_SHARED(sctppcbinfo.ipi_ep_mtx); #endif
* SCTP_INP_RUNLOCK(inp); SCTP_INP_INFO_RUNLOCK(); return
* error; } }
*/
@@ -625,12 +624,24 @@ sctp_assoclist(SYSCTL_HANDLER_ARGS)
TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
number_of_remote_addresses++;
}
- xstcb.remote_port = ntohs(stcb->rport);
+ xstcb.LocalPort = ntohs(inp->sctp_lport);
+ xstcb.RemPort = ntohs(stcb->rport);
+ if (stcb->asoc.primary_destination != NULL)
+ xstcb.RemPrimAddr = stcb->asoc.primary_destination->ro._l_addr;
+ xstcb.HeartBeatInterval = stcb->asoc.heart_beat_delay;
+ xstcb.State = SCTP_GET_STATE(&stcb->asoc); /* FIXME */
+ xstcb.InStreams = stcb->asoc.streamincnt;
+ xstcb.OutStreams = stcb->asoc.streamoutcnt;
+ xstcb.MaxRetr = stcb->asoc.overall_error_count;
+ xstcb.PrimProcess = 0; /* not really supported yet */
+ xstcb.T1expireds = stcb->asoc.timoinit + stcb->asoc.timocookie;
+ xstcb.T2expireds = stcb->asoc.timoshutdown + stcb->asoc.timoshutdownack;
+ xstcb.RtxChunks = stcb->asoc.marked_retrans;
+ xstcb.StartTime = stcb->asoc.start_time;
+ xstcb.DiscontinuityTime = stcb->asoc.discontinuity_time;
+
xstcb.number_local_addresses = number_of_local_addresses;
xstcb.number_remote_addresses = number_of_remote_addresses;
- xstcb.number_incomming_streams = 0;
- xstcb.number_outgoing_streams = 0;
- xstcb.state = stcb->asoc.state;
xstcb.total_sends = stcb->total_sends;
xstcb.total_recvs = stcb->total_recvs;
xstcb.local_tag = stcb->asoc.my_vtag;
@@ -652,15 +663,24 @@ sctp_assoclist(SYSCTL_HANDLER_ARGS)
* &stcb->asoc.sctp_local_addr_list, sctp_nxt_addr)
* { error = SYSCTL_OUT(req, &xladdr, sizeof(struct
* xsctp_laddr)); if (error) { #if
- * defined(SCTP_APPLE_FINE_GRAINED_LOCKING)
- * socket_unlock(inp->ip_inp.inp.inp_socket, 1);
- * lck_rw_unlock_shared(sctppcbinfo.ipi_ep_mtx);
+ * defined(SCTP_PER_SOCKET_LOCKING)
+ * SCTP_SOCKET_UNLOCK(SCTP_INP_SO(inp), 1);
+ * SCTP_UNLOCK_SHARED(sctppcbinfo.ipi_ep_mtx);
* #endif SCTP_INP_RUNLOCK(inp);
* SCTP_INP_INFO_RUNLOCK(); return error; }
* */
TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
- xraddr.state = net->dest_state;
- xraddr.address = net->ro._l_addr;
+ xraddr.RemAddr = net->ro._l_addr;
+ xraddr.RemAddrActive = ((net->dest_state & SCTP_ADDR_REACHABLE) == SCTP_ADDR_REACHABLE);
+ xraddr.RemAddrConfirmed = ((net->dest_state & SCTP_ADDR_UNCONFIRMED) == 0);
+ xraddr.RemAddrHBActive = ((net->dest_state & SCTP_ADDR_NOHB) == 0);
+ xraddr.RemAddrRTO = net->RTO;
+ xraddr.RemAddrMaxPathRtx = net->failure_threshold;
+ xraddr.RemAddrRtx = net->marked_retrans;
+ xraddr.RemAddrErrorCounter = net->error_count;
+ xraddr.RemAddrCwnd = net->cwnd;
+ xraddr.RemAddrFlightSize = net->flight_size;
+ xraddr.RemAddrStartTime = net->start_time;
error = SYSCTL_OUT(req, &xraddr, sizeof(struct xsctp_raddr));
if (error) {
atomic_add_int(&stcb->asoc.refcnt, -1);
@@ -1179,7 +1199,7 @@ sctp_disconnect(struct socket *so)
}
SCTP_INP_RLOCK(inp);
if (inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) {
- if (LIST_EMPTY(&inp->sctp_asoc_list)) {
+ if (SCTP_LIST_EMPTY(&inp->sctp_asoc_list)) {
/* No connection */
SCTP_INP_RUNLOCK(inp);
return (0);
@@ -1240,17 +1260,18 @@ sctp_disconnect(struct socket *so)
if (asoc->locked_on_sending) {
goto abort_anyway;
}
- if ((SCTP_GET_STATE(asoc) !=
- SCTP_STATE_SHUTDOWN_SENT) &&
- (SCTP_GET_STATE(asoc) !=
- SCTP_STATE_SHUTDOWN_ACK_SENT)) {
+ if ((SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_SENT) &&
+ (SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_ACK_SENT)) {
/* only send SHUTDOWN 1st time thru */
sctp_stop_timers_for_shutdown(stcb);
sctp_send_shutdown(stcb,
stcb->asoc.primary_destination);
sctp_chunk_output(stcb->sctp_ep, stcb, SCTP_OUTPUT_FROM_T3);
+ if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) ||
+ (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
+ SCTP_STAT_DECR_GAUGE32(sctps_currestab);
+ }
asoc->state = SCTP_STATE_SHUTDOWN_SENT;
- SCTP_STAT_DECR_GAUGE32(sctps_currestab);
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN,
stcb->sctp_ep, stcb,
asoc->primary_destination);
@@ -1387,8 +1408,11 @@ sctp_shutdown(struct socket *so)
sctp_send_shutdown(stcb,
stcb->asoc.primary_destination);
sctp_chunk_output(stcb->sctp_ep, stcb, SCTP_OUTPUT_FROM_T3);
+ if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) ||
+ (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
+ SCTP_STAT_DECR_GAUGE32(sctps_currestab);
+ }
asoc->state = SCTP_STATE_SHUTDOWN_SENT;
- SCTP_STAT_DECR_GAUGE32(sctps_currestab);
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN,
stcb->sctp_ep, stcb,
asoc->primary_destination);
@@ -1473,15 +1497,16 @@ sctp_fill_user_address(struct sockaddr_storage *ss, struct sockaddr *sa)
-static int
+static size_t
sctp_fill_up_addresses(struct sctp_inpcb *inp,
struct sctp_tcb *stcb,
- int limit,
+ size_t limit,
struct sockaddr_storage *sas)
{
struct ifnet *ifn;
struct ifaddr *ifa;
- int loopback_scope, ipv4_local_scope, local_scope, site_scope, actual;
+ int loopback_scope, ipv4_local_scope, local_scope, site_scope;
+ size_t actual;
int ipv4_addr_legal, ipv6_addr_legal;
actual = 0;
@@ -1716,19 +1741,17 @@ sctp_count_max_addresses(struct sctp_inpcb *inp)
return (cnt);
}
+
static int
-sctp_do_connect_x(struct socket *so,
- struct sctp_inpcb *inp,
- struct mbuf *m,
- struct thread *p,
- int delay
-)
+sctp_do_connect_x(struct socket *so, struct sctp_inpcb *inp, void *optval,
+ size_t optsize, void *p, int delay)
{
int error = 0;
int creat_lock_on = 0;
struct sctp_tcb *stcb = NULL;
struct sockaddr *sa;
- int num_v6 = 0, num_v4 = 0, *totaddrp, totaddr, i, incr, at;
+ int num_v6 = 0, num_v4 = 0, *totaddrp, totaddr, i;
+ size_t incr, at;
#ifdef SCTP_DEBUG
if (sctp_debug_on & SCTP_DEBUG_PCB1) {
@@ -1751,7 +1774,6 @@ sctp_do_connect_x(struct socket *so,
}
if (stcb) {
return (EALREADY);
-
}
SCTP_INP_INCR_REF(inp);
SCTP_ASOC_CREATE_LOCK(inp);
@@ -1761,7 +1783,7 @@ sctp_do_connect_x(struct socket *so,
error = EFAULT;
goto out_now;
}
- totaddrp = mtod(m, int *);
+ totaddrp = (int *)optval;
totaddr = *totaddrp;
sa = (struct sockaddr *)(totaddrp + 1);
at = incr = 0;
@@ -1794,7 +1816,7 @@ sctp_do_connect_x(struct socket *so,
error = EALREADY;
goto out_now;
}
- if ((at + incr) > SCTP_BUF_LEN(m)) {
+ if ((at + incr) > optsize) {
totaddr = i;
break;
}
@@ -1892,34 +1914,49 @@ out_now:
return error;
}
+#define SCTP_FIND_STCB(inp, stcb, assoc_id) \
+ if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) { \
+ SCTP_INP_RLOCK(inp); \
+ stcb = LIST_FIRST(&inp->sctp_asoc_list); \
+ if (stcb) \
+ SCTP_TCB_LOCK(stcb); \
+ SCTP_INP_RUNLOCK(inp); \
+ } else if (assoc_id != 0) { \
+ stcb = sctp_findassociation_ep_asocid(inp, assoc_id, 1); \
+ if (stcb == NULL) { \
+ error = ENOENT; \
+ break; \
+ } \
+ } else { \
+ stcb = NULL; \
+ }
+
+#define SCTP_CHECK_AND_CAST(destp, srcp, type, size) \
+ if (size < sizeof(type)) { \
+ error = EINVAL; \
+ break; \
+ } else { \
+ destp = (type *)srcp; \
+ }
static int
-sctp_optsget(struct socket *so,
- int opt,
- struct mbuf **mp,
- struct thread *p
-)
+sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
+ void *p)
{
struct sctp_inpcb *inp;
- struct mbuf *m;
- int error, optval = 0;
+ int error, val = 0;
struct sctp_tcb *stcb = NULL;
+ if (optval == NULL) {
+ return (EINVAL);
+ }
inp = (struct sctp_inpcb *)so->so_pcb;
if (inp == 0)
return EINVAL;
error = 0;
- if (mp == NULL) {
- return (EINVAL);
- }
- m = *mp;
- if (m == NULL) {
- /* Got to have a mbuf */
- return (EINVAL);
- }
- switch (opt) {
+ switch (optname) {
case SCTP_NODELAY:
case SCTP_AUTOCLOSE:
case SCTP_EXPLICIT_EOR:
@@ -1928,94 +1965,92 @@ sctp_optsget(struct socket *so,
case SCTP_I_WANT_MAPPED_V4_ADDR:
case SCTP_USE_EXT_RCVINFO:
SCTP_INP_RLOCK(inp);
- switch (opt) {
+ switch (optname) {
case SCTP_DISABLE_FRAGMENTS:
- optval = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NO_FRAGMENT);
+ val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NO_FRAGMENT);
break;
case SCTP_I_WANT_MAPPED_V4_ADDR:
- optval = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4);
+ val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4);
break;
case SCTP_AUTO_ASCONF:
- optval = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_AUTO_ASCONF);
+ val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_AUTO_ASCONF);
break;
case SCTP_EXPLICIT_EOR:
- optval = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXPLICIT_EOR);
+ val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXPLICIT_EOR);
break;
case SCTP_NODELAY:
- optval = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NODELAY);
+ val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NODELAY);
break;
case SCTP_USE_EXT_RCVINFO:
- optval = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXT_RCVINFO);
+ val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXT_RCVINFO);
break;
case SCTP_AUTOCLOSE:
if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_AUTOCLOSE))
- optval = TICKS_TO_SEC(inp->sctp_ep.auto_close_time);
+ val = TICKS_TO_SEC(inp->sctp_ep.auto_close_time);
else
- optval = 0;
+ val = 0;
break;
default:
error = ENOPROTOOPT;
} /* end switch (sopt->sopt_name) */
- if (opt != SCTP_AUTOCLOSE) {
+ if (optname != SCTP_AUTOCLOSE) {
/* make it an "on/off" value */
- optval = (optval != 0);
+ val = (val != 0);
}
- if ((size_t)SCTP_BUF_LEN(m) < sizeof(int)) {
+ if (*optsize < sizeof(val)) {
error = EINVAL;
}
SCTP_INP_RUNLOCK(inp);
if (error == 0) {
/* return the option value */
- *mtod(m, int *)= optval;
- SCTP_BUF_LEN(m) = sizeof(optval);
+ *(int *)optval = val;
+ *optsize = sizeof(val);
}
break;
case SCTP_PARTIAL_DELIVERY_POINT:
{
- if ((size_t)SCTP_BUF_LEN(m) < sizeof(unsigned int)) {
- error = EINVAL;
- break;
- }
- *mtod(m, unsigned int *)= inp->partial_delivery_point;
- SCTP_BUF_LEN(m) = sizeof(unsigned int);
+ uint32_t *value;
+
+ SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize);
+ *value = inp->partial_delivery_point;
+ *optsize = sizeof(uint32_t);
}
break;
case SCTP_FRAGMENT_INTERLEAVE:
{
- if ((size_t)SCTP_BUF_LEN(m) < sizeof(unsigned int)) {
- error = EINVAL;
- break;
- }
- *mtod(m, unsigned int *)= sctp_is_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE);
- SCTP_BUF_LEN(m) = sizeof(unsigned int);
+ uint32_t *value;
+
+ SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize);
+ *value = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE);
+ *optsize = sizeof(uint32_t);
}
break;
case SCTP_CMT_ON_OFF:
{
- if ((size_t)SCTP_BUF_LEN(m) < sizeof(unsigned int)) {
- error = EINVAL;
- break;
+ struct sctp_assoc_value *av;
+
+ SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
+ if (sctp_cmt_on_off) {
+ SCTP_FIND_STCB(inp, stcb, av->assoc_id);
+ if (stcb) {
+ av->assoc_value = stcb->asoc.sctp_cmt_on_off;
+ SCTP_TCB_UNLOCK(stcb);
+
+ } else {
+ error = ENOTCONN;
+ }
+ } else {
+ error = ENOPROTOOPT;
}
- *mtod(m, unsigned int *)= sctp_cmt_sockopt_on_off;
- SCTP_BUF_LEN(m) = sizeof(unsigned int);
- }
- break;
- case SCTP_CMT_USE_DAC:
- {
- *mtod(m, unsigned int *)= sctp_cmt_sockopt_use_dac;
- SCTP_BUF_LEN(m) = sizeof(unsigned int);
+ *optsize = sizeof(*av);
}
break;
case SCTP_GET_ADDR_LEN:
{
struct sctp_assoc_value *av;
- if ((size_t)SCTP_BUF_LEN(m) < sizeof(struct sctp_assoc_value)) {
- error = EINVAL;
- break;
- }
- av = mtod(m, struct sctp_assoc_value *);
+ SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
error = EINVAL;
#ifdef AF_INET
if (av->assoc_value == AF_INET) {
@@ -2029,6 +2064,7 @@ sctp_optsget(struct socket *so,
error = 0;
}
#endif
+ *optsize = sizeof(*av);
}
break;
case SCTP_GET_ASOC_ID_LIST:
@@ -2037,11 +2073,7 @@ sctp_optsget(struct socket *so,
int cnt, at;
uint16_t orig;
- if ((size_t)SCTP_BUF_LEN(m) < sizeof(struct sctp_assoc_ids)) {
- error = EINVAL;
- break;
- }
- ids = mtod(m, struct sctp_assoc_ids *);
+ SCTP_CHECK_AND_CAST(ids, optval, struct sctp_assoc_ids, *optsize);
cnt = 0;
SCTP_INP_RLOCK(inp);
stcb = LIST_FIRST(&inp->sctp_asoc_list);
@@ -2082,192 +2114,112 @@ sctp_optsget(struct socket *so,
break;
case SCTP_CONTEXT:
{
-
struct sctp_assoc_value *av;
- if ((size_t)SCTP_BUF_LEN(m) < sizeof(struct sctp_assoc_value)) {
- error = EINVAL;
- break;
- }
- av = mtod(m, struct sctp_assoc_value *);
- if (av->assoc_id) {
- stcb = sctp_findassociation_ep_asocid(inp, av->assoc_id, 1);
- if (stcb == NULL) {
- error = ENOTCONN;
- } else {
- av->assoc_value = stcb->asoc.context;
- SCTP_TCB_UNLOCK(stcb);
- }
+ SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
+ SCTP_FIND_STCB(inp, stcb, av->assoc_id);
+
+ if (stcb) {
+ av->assoc_value = stcb->asoc.context;
+ SCTP_TCB_UNLOCK(stcb);
} else {
+ SCTP_INP_RLOCK(inp);
av->assoc_value = inp->sctp_context;
+ SCTP_INP_RUNLOCK(inp);
}
+ *optsize = sizeof(*av);
}
break;
case SCTP_GET_NONCE_VALUES:
{
struct sctp_get_nonce_values *gnv;
- if ((size_t)SCTP_BUF_LEN(m) < sizeof(struct sctp_get_nonce_values)) {
- error = EINVAL;
- break;
- }
- gnv = mtod(m, struct sctp_get_nonce_values *);
- stcb = sctp_findassociation_ep_asocid(inp, gnv->gn_assoc_id, 1);
- if (stcb == NULL) {
- error = ENOTCONN;
- } else {
+ SCTP_CHECK_AND_CAST(gnv, optval, struct sctp_get_nonce_values, *optsize);
+ SCTP_FIND_STCB(inp, stcb, gnv->gn_assoc_id);
+
+ if (stcb) {
gnv->gn_peers_tag = stcb->asoc.peer_vtag;
gnv->gn_local_tag = stcb->asoc.my_vtag;
SCTP_TCB_UNLOCK(stcb);
+ } else {
+ error = ENOTCONN;
}
-
+ *optsize = sizeof(*gnv);
}
break;
case SCTP_DELAYED_ACK_TIME:
{
struct sctp_assoc_value *tm;
- if ((size_t)SCTP_BUF_LEN(m) < sizeof(struct sctp_assoc_value)) {
- error = EINVAL;
- break;
- }
- tm = mtod(m, struct sctp_assoc_value *);
+ SCTP_CHECK_AND_CAST(tm, optval, struct sctp_assoc_value, *optsize);
+ SCTP_FIND_STCB(inp, stcb, tm->assoc_id);
- if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
+ if (stcb) {
+ tm->assoc_value = stcb->asoc.delayed_ack;
+ SCTP_TCB_UNLOCK(stcb);
+ } else {
SCTP_INP_RLOCK(inp);
- stcb = LIST_FIRST(&inp->sctp_asoc_list);
- if (stcb) {
- SCTP_TCB_LOCK(stcb);
- tm->assoc_value = stcb->asoc.delayed_ack;
- SCTP_TCB_UNLOCK(stcb);
- } else {
- tm->assoc_value = TICKS_TO_MSEC(inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_RECV]);
- }
+ tm->assoc_value = TICKS_TO_MSEC(inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_RECV]);
SCTP_INP_RUNLOCK(inp);
- } else {
- stcb = sctp_findassociation_ep_asocid(inp, tm->assoc_id, 1);
- if (stcb == NULL) {
- error = ENOTCONN;
- tm->assoc_value = 0;
- } else {
- stcb->asoc.delayed_ack = tm->assoc_value;
- SCTP_TCB_UNLOCK(stcb);
- }
}
+ *optsize = sizeof(*tm);
}
break;
case SCTP_GET_SNDBUF_USE:
- if ((size_t)SCTP_BUF_LEN(m) < sizeof(struct sctp_sockstat)) {
- error = EINVAL;
- } else {
+ {
struct sctp_sockstat *ss;
- struct sctp_tcb *stcb;
- struct sctp_association *asoc;
- ss = mtod(m, struct sctp_sockstat *);
- stcb = sctp_findassociation_ep_asocid(inp, ss->ss_assoc_id, 1);
- if (stcb == NULL) {
- error = ENOTCONN;
- } else {
- asoc = &stcb->asoc;
- ss->ss_total_sndbuf = (uint32_t) asoc->total_output_queue_size;
- ss->ss_total_recv_buf = (uint32_t) (asoc->size_on_reasm_queue +
- asoc->size_on_all_streams);
+ SCTP_CHECK_AND_CAST(ss, optval, struct sctp_sockstat, *optsize);
+ SCTP_FIND_STCB(inp, stcb, ss->ss_assoc_id);
+
+ if (stcb) {
+ ss->ss_total_sndbuf = stcb->asoc.total_output_queue_size;
+ ss->ss_total_recv_buf = (stcb->asoc.size_on_reasm_queue +
+ stcb->asoc.size_on_all_streams);
SCTP_TCB_UNLOCK(stcb);
- error = 0;
- SCTP_BUF_LEN(m) = sizeof(struct sctp_sockstat);
+ } else {
+ error = ENOTCONN;
}
+ *optsize = sizeof(struct sctp_sockstat);
}
break;
case SCTP_MAXBURST:
{
- uint8_t *burst;
+ uint8_t *value;
+
+ SCTP_CHECK_AND_CAST(value, optval, uint8_t, *optsize);
- burst = mtod(m, uint8_t *);
SCTP_INP_RLOCK(inp);
- *burst = inp->sctp_ep.max_burst;
+ *value = inp->sctp_ep.max_burst;
SCTP_INP_RUNLOCK(inp);
- SCTP_BUF_LEN(m) = sizeof(uint8_t);
+ *optsize = sizeof(uint8_t);
}
break;
-
+ /*
+ * FIXME MT: Should this be done as the association level by
+ * using sctp_get_frag_point?
+ */
case SCTP_MAXSEG:
{
uint32_t *segsize;
- sctp_assoc_t *assoc_id;
int ovh;
- if ((size_t)SCTP_BUF_LEN(m) < sizeof(uint32_t)) {
- error = EINVAL;
- break;
- }
- if ((size_t)SCTP_BUF_LEN(m) < sizeof(sctp_assoc_t)) {
- error = EINVAL;
- break;
- }
- assoc_id = mtod(m, sctp_assoc_t *);
- segsize = mtod(m, uint32_t *);
- SCTP_BUF_LEN(m) = sizeof(uint32_t);
-
- if (((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) &&
- (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) ||
- (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) {
- struct sctp_tcb *stcb;
+ SCTP_CHECK_AND_CAST(segsize, optval, uint32_t, *optsize);
- SCTP_INP_RLOCK(inp);
- stcb = LIST_FIRST(&inp->sctp_asoc_list);
- if (stcb) {
- SCTP_TCB_LOCK(stcb);
- SCTP_INP_RUNLOCK(inp);
- *segsize = sctp_get_frag_point(stcb, &stcb->asoc);
- SCTP_TCB_UNLOCK(stcb);
- } else {
- SCTP_INP_RUNLOCK(inp);
- goto skipit;
- }
+ SCTP_INP_RLOCK(inp);
+ if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
+ ovh = SCTP_MED_OVERHEAD;
} else {
- stcb = sctp_findassociation_ep_asocid(inp, *assoc_id, 1);
- if (stcb) {
- *segsize = sctp_get_frag_point(stcb, &stcb->asoc);
- SCTP_TCB_UNLOCK(stcb);
- break;
- }
- skipit:
- /*
- * default is to get the max, if I can't
- * calculate from an existing association.
- */
- if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
- ovh = SCTP_MED_OVERHEAD;
- } else {
- ovh = SCTP_MED_V4_OVERHEAD;
- }
- *segsize = inp->sctp_frag_point - ovh;
- }
- }
- break;
-
- case SCTP_SET_DEBUG_LEVEL:
-#ifdef SCTP_DEBUG
- {
- uint32_t *level;
-
- if ((size_t)SCTP_BUF_LEN(m) < sizeof(uint32_t)) {
- error = EINVAL;
- break;
+ ovh = SCTP_MED_V4_OVERHEAD;
}
- level = mtod(m, uint32_t *);
- error = 0;
- *level = sctp_debug_on;
- SCTP_BUF_LEN(m) = sizeof(uint32_t);
- printf("Returning DEBUG LEVEL %x is set\n",
- (uint32_t) sctp_debug_on);
+ *segsize = inp->sctp_frag_point - ovh;
+ SCTP_INP_RUNLOCK(inp);
+ *optsize = sizeof(uint32_t);
}
-#else /* SCTP_DEBUG */
- error = EOPNOTSUPP;
-#endif
break;
+#if 0
+ /* FIXME MT: How does this work? */
case SCTP_GET_STAT_LOG:
#ifdef SCTP_STAT_LOGGING
error = sctp_fill_stat_log(m);
@@ -2275,15 +2227,12 @@ sctp_optsget(struct socket *so,
error = EOPNOTSUPP;
#endif
break;
+#endif
case SCTP_EVENTS:
{
struct sctp_event_subscribe *events;
- if ((size_t)SCTP_BUF_LEN(m) < sizeof(struct sctp_event_subscribe)) {
- error = EINVAL;
- break;
- }
- events = mtod(m, struct sctp_event_subscribe *);
+ SCTP_CHECK_AND_CAST(events, optval, struct sctp_event_subscribe, *optsize);
memset(events, 0, sizeof(*events));
SCTP_INP_RLOCK(inp);
if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVDATAIOEVNT))
@@ -2316,85 +2265,74 @@ sctp_optsget(struct socket *so,
if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_STREAM_RESETEVNT))
events->sctp_stream_reset_events = 1;
SCTP_INP_RUNLOCK(inp);
- SCTP_BUF_LEN(m) = sizeof(struct sctp_event_subscribe);
-
+ *optsize = sizeof(struct sctp_event_subscribe);
}
break;
case SCTP_ADAPTATION_LAYER:
- if ((size_t)SCTP_BUF_LEN(m) < sizeof(int)) {
- error = EINVAL;
- break;
+ {
+ uint32_t *value;
+
+ SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize);
+
+ SCTP_INP_RLOCK(inp);
+ *value = inp->sctp_ep.adaptation_layer_indicator;
+ SCTP_INP_RUNLOCK(inp);
+ *optsize = sizeof(uint32_t);
}
- SCTP_INP_RLOCK(inp);
- *mtod(m, int *)= inp->sctp_ep.adaptation_layer_indicator;
- SCTP_INP_RUNLOCK(inp);
- SCTP_BUF_LEN(m) = sizeof(int);
break;
case SCTP_SET_INITIAL_DBG_SEQ:
- if ((size_t)SCTP_BUF_LEN(m) < sizeof(int)) {
- error = EINVAL;
- break;
+ {
+ uint32_t *value;
+
+ SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize);
+ SCTP_INP_RLOCK(inp);
+ *value = inp->sctp_ep.initial_sequence_debug;
+ SCTP_INP_RUNLOCK(inp);
+ *optsize = sizeof(uint32_t);
}
- SCTP_INP_RLOCK(inp);
- *mtod(m, int *)= inp->sctp_ep.initial_sequence_debug;
- SCTP_INP_RUNLOCK(inp);
- SCTP_BUF_LEN(m) = sizeof(int);
break;
case SCTP_GET_LOCAL_ADDR_SIZE:
- if ((size_t)SCTP_BUF_LEN(m) < sizeof(int)) {
- error = EINVAL;
- break;
+ {
+ uint32_t *value;
+
+ SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize);
+ SCTP_INP_RLOCK(inp);
+ *value = sctp_count_max_addresses(inp);
+ SCTP_INP_RUNLOCK(inp);
+ *optsize = sizeof(uint32_t);
}
- SCTP_INP_RLOCK(inp);
- *mtod(m, int *)= sctp_count_max_addresses(inp);
- SCTP_INP_RUNLOCK(inp);
- SCTP_BUF_LEN(m) = sizeof(int);
break;
case SCTP_GET_REMOTE_ADDR_SIZE:
{
- sctp_assoc_t *assoc_id;
- uint32_t *val, sz;
+ uint32_t *value;
+ size_t size;
struct sctp_nets *net;
- if ((size_t)SCTP_BUF_LEN(m) < sizeof(sctp_assoc_t)) {
- error = EINVAL;
- break;
- }
- stcb = NULL;
- val = mtod(m, uint32_t *);
- if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
- SCTP_INP_RLOCK(inp);
- stcb = LIST_FIRST(&inp->sctp_asoc_list);
- if (stcb)
- SCTP_TCB_LOCK(stcb);
- SCTP_INP_RUNLOCK(inp);
- }
- if (stcb == NULL) {
- assoc_id = mtod(m, sctp_assoc_t *);
- stcb = sctp_findassociation_ep_asocid(inp, *assoc_id, 1);
- }
- if (stcb == NULL) {
- error = EINVAL;
- break;
- }
- *val = 0;
- sz = 0;
- /* Count the sizes */
- TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
- if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_NEEDS_MAPPED_V4) ||
- (((struct sockaddr *)&net->ro._l_addr)->sa_family == AF_INET6)) {
- sz += sizeof(struct sockaddr_in6);
- } else if (((struct sockaddr *)&net->ro._l_addr)->sa_family == AF_INET) {
- sz += sizeof(struct sockaddr_in);
- } else {
- /* huh */
- break;
+ SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize);
+ /* FIXME MT: change to sctp_assoc_value? */
+ SCTP_FIND_STCB(inp, stcb, (sctp_assoc_t) * value);
+
+ if (stcb) {
+ size = 0;
+ /* Count the sizes */
+ TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
+ if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_NEEDS_MAPPED_V4) ||
+ (((struct sockaddr *)&net->ro._l_addr)->sa_family == AF_INET6)) {
+ size += sizeof(struct sockaddr_in6);
+ } else if (((struct sockaddr *)&net->ro._l_addr)->sa_family == AF_INET) {
+ size += sizeof(struct sockaddr_in);
+ } else {
+ /* huh */
+ break;
+ }
}
+ SCTP_TCB_UNLOCK(stcb);
+ *value = (uint32_t) size;
+ } else {
+ error = ENOTCONN;
}
- SCTP_TCB_UNLOCK(stcb);
- *val = sz;
- SCTP_BUF_LEN(m) = sizeof(uint32_t);
+ *optsize = sizeof(uint32_t);
}
break;
case SCTP_GET_PEER_ADDRESSES:
@@ -2403,107 +2341,68 @@ sctp_optsget(struct socket *so,
* fill up we pack it.
*/
{
- int cpsz, left;
+ size_t cpsz, left;
struct sockaddr_storage *sas;
struct sctp_nets *net;
struct sctp_getaddresses *saddr;
- if ((size_t)SCTP_BUF_LEN(m) < sizeof(struct sctp_getaddresses)) {
- error = EINVAL;
- break;
- }
- left = SCTP_BUF_LEN(m) - sizeof(struct sctp_getaddresses);
- saddr = mtod(m, struct sctp_getaddresses *);
- if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
- SCTP_INP_RLOCK(inp);
- stcb = LIST_FIRST(&inp->sctp_asoc_list);
- if (stcb)
- SCTP_TCB_LOCK(stcb);
- SCTP_INP_RUNLOCK(inp);
- } else
- stcb = sctp_findassociation_ep_asocid(inp,
- saddr->sget_assoc_id, 1);
- if (stcb == NULL) {
- error = ENOENT;
- break;
- }
- SCTP_BUF_LEN(m) = sizeof(struct sctp_getaddresses);
- sas = (struct sockaddr_storage *)&saddr->addr[0];
+ SCTP_CHECK_AND_CAST(saddr, optval, struct sctp_getaddresses, *optsize);
+ SCTP_FIND_STCB(inp, stcb, saddr->sget_assoc_id);
- TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
- if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_NEEDS_MAPPED_V4) ||
- (((struct sockaddr *)&net->ro._l_addr)->sa_family == AF_INET6)) {
- cpsz = sizeof(struct sockaddr_in6);
- } else if (((struct sockaddr *)&net->ro._l_addr)->sa_family == AF_INET) {
- cpsz = sizeof(struct sockaddr_in);
- } else {
- /* huh */
- break;
- }
- if (left < cpsz) {
- /* not enough room. */
- break;
- }
- if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_NEEDS_MAPPED_V4) &&
- (((struct sockaddr *)&net->ro._l_addr)->sa_family == AF_INET)) {
- /* Must map the address */
- in6_sin_2_v4mapsin6((struct sockaddr_in *)&net->ro._l_addr,
- (struct sockaddr_in6 *)sas);
- } else {
- memcpy(sas, &net->ro._l_addr, cpsz);
- }
- ((struct sockaddr_in *)sas)->sin_port = stcb->rport;
+ if (stcb) {
+ left = (*optsize) - sizeof(struct sctp_getaddresses);
+ *optsize = sizeof(struct sctp_getaddresses);
+ sas = (struct sockaddr_storage *)&saddr->addr[0];
- sas = (struct sockaddr_storage *)((caddr_t)sas + cpsz);
- left -= cpsz;
- SCTP_BUF_LEN(m) += cpsz;
+ TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
+ if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_NEEDS_MAPPED_V4) ||
+ (((struct sockaddr *)&net->ro._l_addr)->sa_family == AF_INET6)) {
+ cpsz = sizeof(struct sockaddr_in6);
+ } else if (((struct sockaddr *)&net->ro._l_addr)->sa_family == AF_INET) {
+ cpsz = sizeof(struct sockaddr_in);
+ } else {
+ /* huh */
+ break;
+ }
+ if (left < cpsz) {
+ /* not enough room. */
+ break;
+ }
+ if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_NEEDS_MAPPED_V4) &&
+ (((struct sockaddr *)&net->ro._l_addr)->sa_family == AF_INET)) {
+ /* Must map the address */
+ in6_sin_2_v4mapsin6((struct sockaddr_in *)&net->ro._l_addr,
+ (struct sockaddr_in6 *)sas);
+ } else {
+ memcpy(sas, &net->ro._l_addr, cpsz);
+ }
+ ((struct sockaddr_in *)sas)->sin_port = stcb->rport;
+
+ sas = (struct sockaddr_storage *)((caddr_t)sas + cpsz);
+ left -= cpsz;
+ *optsize += cpsz;
+ }
+ SCTP_TCB_UNLOCK(stcb);
+ } else {
+ error = ENOENT;
}
- SCTP_TCB_UNLOCK(stcb);
}
break;
case SCTP_GET_LOCAL_ADDRESSES:
{
- int limit, actual;
+ size_t limit, actual;
struct sockaddr_storage *sas;
struct sctp_getaddresses *saddr;
- if ((size_t)SCTP_BUF_LEN(m) < sizeof(struct sctp_getaddresses)) {
- error = EINVAL;
- break;
- }
- saddr = mtod(m, struct sctp_getaddresses *);
-
- if (saddr->sget_assoc_id) {
- if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
- SCTP_INP_RLOCK(inp);
- stcb = LIST_FIRST(&inp->sctp_asoc_list);
- if (stcb)
- SCTP_TCB_LOCK(stcb);
- SCTP_INP_RUNLOCK(inp);
- } else
- stcb = sctp_findassociation_ep_asocid(inp, saddr->sget_assoc_id, 1);
+ SCTP_CHECK_AND_CAST(saddr, optval, struct sctp_getaddresses, *optsize);
+ SCTP_FIND_STCB(inp, stcb, saddr->sget_assoc_id);
- } else {
- stcb = NULL;
- }
- /*
- * assure that the TCP model does not need a assoc
- * id once connected.
- */
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) &&
- (stcb == NULL)) {
- SCTP_INP_RLOCK(inp);
- stcb = LIST_FIRST(&inp->sctp_asoc_list);
- if (stcb)
- SCTP_TCB_LOCK(stcb);
- SCTP_INP_RUNLOCK(inp);
- }
sas = (struct sockaddr_storage *)&saddr->addr[0];
- limit = SCTP_BUF_LEN(m) - sizeof(sctp_assoc_t);
+ limit = *optsize - sizeof(sctp_assoc_t);
actual = sctp_fill_up_addresses(inp, stcb, limit, sas);
if (stcb)
SCTP_TCB_UNLOCK(stcb);
- SCTP_BUF_LEN(m) = sizeof(struct sockaddr_storage) + actual;
+ *optsize = sizeof(struct sockaddr_storage) + actual;
}
break;
case SCTP_PEER_ADDR_PARAMS:
@@ -2511,57 +2410,27 @@ sctp_optsget(struct socket *so,
struct sctp_paddrparams *paddrp;
struct sctp_nets *net;
- if ((size_t)SCTP_BUF_LEN(m) < sizeof(struct sctp_paddrparams)) {
- error = EINVAL;
- break;
- }
- paddrp = mtod(m, struct sctp_paddrparams *);
+ SCTP_CHECK_AND_CAST(paddrp, optval, struct sctp_paddrparams, *optsize);
+ SCTP_FIND_STCB(inp, stcb, paddrp->spp_assoc_id);
net = NULL;
- if (paddrp->spp_assoc_id) {
- if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
- SCTP_INP_RLOCK(inp);
- stcb = LIST_FIRST(&inp->sctp_asoc_list);
- if (stcb) {
- SCTP_TCB_LOCK(stcb);
- net = sctp_findnet(stcb, (struct sockaddr *)&paddrp->spp_address);
- }
- SCTP_INP_RLOCK(inp);
- } else {
- stcb = sctp_findassociation_ep_asocid(inp, paddrp->spp_assoc_id, 1);
- }
+ if (stcb) {
+ net = sctp_findnet(stcb, (struct sockaddr *)&paddrp->spp_address);
+ } else {
+ /*
+ * We increment here since
+ * sctp_findassociation_ep_addr() wil do a
+ * decrement if it finds the stcb as long as
+ * the locked tcb (last argument) is NOT a
+ * TCB.. aka NULL.
+ */
+ SCTP_INP_INCR_REF(inp);
+ stcb = sctp_findassociation_ep_addr(&inp, (struct sockaddr *)&paddrp->spp_address, &net, NULL, NULL);
if (stcb == NULL) {
- error = ENOENT;
- break;
+ SCTP_INP_DECR_REF(inp);
}
}
- if ((stcb == NULL) &&
- ((((struct sockaddr *)&paddrp->spp_address)->sa_family == AF_INET) ||
- (((struct sockaddr *)&paddrp->spp_address)->sa_family == AF_INET6))) {
- /* Lookup via address */
- if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
- SCTP_INP_RLOCK(inp);
- stcb = LIST_FIRST(&inp->sctp_asoc_list);
- if (stcb) {
- SCTP_TCB_LOCK(stcb);
- net = sctp_findnet(stcb, (struct sockaddr *)&paddrp->spp_address);
- }
- SCTP_INP_RUNLOCK(inp);
- } else {
- SCTP_INP_INCR_REF(inp);
- stcb = sctp_findassociation_ep_addr(&inp,
- (struct sockaddr *)&paddrp->spp_address,
- &net, NULL, NULL);
- if (stcb == NULL) {
- SCTP_INP_DECR_REF(inp);
- }
- }
- if (stcb == NULL) {
- error = ENOENT;
- break;
- }
- }
if (stcb) {
/* Applys to the specific association */
paddrp->spp_flags = 0;
@@ -2646,7 +2515,7 @@ sctp_optsget(struct socket *so,
SCTP_INP_RUNLOCK(inp);
}
- SCTP_BUF_LEN(m) = sizeof(struct sctp_paddrparams);
+ *optsize = sizeof(struct sctp_paddrparams);
}
break;
case SCTP_GET_PEER_ADDR_INFO:
@@ -2654,64 +2523,50 @@ sctp_optsget(struct socket *so,
struct sctp_paddrinfo *paddri;
struct sctp_nets *net;
- if ((size_t)SCTP_BUF_LEN(m) < sizeof(struct sctp_paddrinfo)) {
- error = EINVAL;
- break;
- }
- paddri = mtod(m, struct sctp_paddrinfo *);
+ SCTP_CHECK_AND_CAST(paddri, optval, struct sctp_paddrinfo, *optsize);
+ SCTP_FIND_STCB(inp, stcb, paddri->spinfo_assoc_id);
+
net = NULL;
- if ((((struct sockaddr *)&paddri->spinfo_address)->sa_family == AF_INET) ||
- (((struct sockaddr *)&paddri->spinfo_address)->sa_family == AF_INET6)) {
- /* Lookup via address */
- if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
- SCTP_INP_RLOCK(inp);
- stcb = LIST_FIRST(&inp->sctp_asoc_list);
- if (stcb) {
- SCTP_TCB_LOCK(stcb);
- net = sctp_findnet(stcb,
- (struct sockaddr *)&paddri->spinfo_address);
- }
- SCTP_INP_RUNLOCK(inp);
- } else {
- SCTP_INP_INCR_REF(inp);
- stcb = sctp_findassociation_ep_addr(&inp,
- (struct sockaddr *)&paddri->spinfo_address,
- &net, NULL, NULL);
- if (stcb == NULL) {
- SCTP_INP_DECR_REF(inp);
- }
+ if (stcb) {
+ net = sctp_findnet(stcb, (struct sockaddr *)&paddri->spinfo_address);
+ } else {
+ /*
+ * We increment here since
+ * sctp_findassociation_ep_addr() wil do a
+ * decrement if it finds the stcb as long as
+ * the locked tcb (last argument) is NOT a
+ * TCB.. aka NULL.
+ */
+ SCTP_INP_INCR_REF(inp);
+ stcb = sctp_findassociation_ep_addr(&inp, (struct sockaddr *)&paddri->spinfo_address, &net, NULL, NULL);
+ if (stcb == NULL) {
+ SCTP_INP_DECR_REF(inp);
}
+ }
+ if ((stcb) && (net)) {
+ paddri->spinfo_state = net->dest_state & (SCTP_REACHABLE_MASK | SCTP_ADDR_NOHB);
+ paddri->spinfo_cwnd = net->cwnd;
+ paddri->spinfo_srtt = ((net->lastsa >> 2) + net->lastsv) >> 1;
+ paddri->spinfo_rto = net->RTO;
+ paddri->spinfo_assoc_id = sctp_get_associd(stcb);
+ SCTP_TCB_UNLOCK(stcb);
} else {
- stcb = NULL;
- }
- if ((stcb == NULL) || (net == NULL)) {
if (stcb) {
SCTP_TCB_UNLOCK(stcb);
}
error = ENOENT;
- break;
}
- SCTP_BUF_LEN(m) = sizeof(struct sctp_paddrinfo);
- paddri->spinfo_state = net->dest_state & (SCTP_REACHABLE_MASK | SCTP_ADDR_NOHB);
- paddri->spinfo_cwnd = net->cwnd;
- paddri->spinfo_srtt = ((net->lastsa >> 2) + net->lastsv) >> 1;
- paddri->spinfo_rto = net->RTO;
- paddri->spinfo_assoc_id = sctp_get_associd(stcb);
- SCTP_TCB_UNLOCK(stcb);
+ *optsize = sizeof(struct sctp_paddrinfo);
}
break;
case SCTP_PCB_STATUS:
{
struct sctp_pcbinfo *spcb;
- if ((size_t)SCTP_BUF_LEN(m) < sizeof(struct sctp_pcbinfo)) {
- error = EINVAL;
- break;
- }
- spcb = mtod(m, struct sctp_pcbinfo *);
+ SCTP_CHECK_AND_CAST(spcb, optval, struct sctp_pcbinfo, *optsize);
sctp_fill_pcbinfo(spcb);
- SCTP_BUF_LEN(m) = sizeof(struct sctp_pcbinfo);
+ *optsize = sizeof(struct sctp_pcbinfo);
}
break;
case SCTP_STATUS:
@@ -2719,20 +2574,8 @@ sctp_optsget(struct socket *so,
struct sctp_nets *net;
struct sctp_status *sstat;
- if ((size_t)SCTP_BUF_LEN(m) < sizeof(struct sctp_status)) {
- error = EINVAL;
- break;
- }
- sstat = mtod(m, struct sctp_status *);
-
- if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
- SCTP_INP_RLOCK(inp);
- stcb = LIST_FIRST(&inp->sctp_asoc_list);
- if (stcb)
- SCTP_TCB_LOCK(stcb);
- SCTP_INP_RUNLOCK(inp);
- } else
- stcb = sctp_findassociation_ep_asocid(inp, sstat->sstat_assoc_id, 1);
+ SCTP_CHECK_AND_CAST(sstat, optval, struct sctp_status, *optsize);
+ SCTP_FIND_STCB(inp, stcb, sstat->sstat_assoc_id);
if (stcb == NULL) {
error = EINVAL;
@@ -2773,76 +2616,38 @@ sctp_optsget(struct socket *so,
sstat->sstat_primary.spinfo_mtu = net->mtu;
sstat->sstat_primary.spinfo_assoc_id = sctp_get_associd(stcb);
SCTP_TCB_UNLOCK(stcb);
- SCTP_BUF_LEN(m) = sizeof(*sstat);
+ *optsize = sizeof(*sstat);
}
break;
case SCTP_RTOINFO:
{
struct sctp_rtoinfo *srto;
- if ((size_t)SCTP_BUF_LEN(m) < sizeof(struct sctp_rtoinfo)) {
- error = EINVAL;
- break;
- }
- srto = mtod(m, struct sctp_rtoinfo *);
- if (srto->srto_assoc_id == 0) {
- /* Endpoint only please */
+ SCTP_CHECK_AND_CAST(srto, optval, struct sctp_rtoinfo, *optsize);
+ SCTP_FIND_STCB(inp, stcb, srto->srto_assoc_id);
+
+ if (stcb) {
+ srto->srto_initial = stcb->asoc.initial_rto;
+ srto->srto_max = stcb->asoc.maxrto;
+ srto->srto_min = stcb->asoc.minrto;
+ SCTP_TCB_UNLOCK(stcb);
+ } else {
SCTP_INP_RLOCK(inp);
srto->srto_initial = inp->sctp_ep.initial_rto;
srto->srto_max = inp->sctp_ep.sctp_maxrto;
srto->srto_min = inp->sctp_ep.sctp_minrto;
SCTP_INP_RUNLOCK(inp);
- break;
- }
- if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
- SCTP_INP_RLOCK(inp);
- stcb = LIST_FIRST(&inp->sctp_asoc_list);
- if (stcb)
- SCTP_TCB_LOCK(stcb);
- SCTP_INP_RUNLOCK(inp);
- } else
- stcb = sctp_findassociation_ep_asocid(inp, srto->srto_assoc_id, 1);
-
- if (stcb == NULL) {
- error = EINVAL;
- break;
}
- srto->srto_initial = stcb->asoc.initial_rto;
- srto->srto_max = stcb->asoc.maxrto;
- srto->srto_min = stcb->asoc.minrto;
- SCTP_TCB_UNLOCK(stcb);
- SCTP_BUF_LEN(m) = sizeof(*srto);
+ *optsize = sizeof(*srto);
}
break;
case SCTP_ASSOCINFO:
{
struct sctp_assocparams *sasoc;
- if ((size_t)SCTP_BUF_LEN(m) < sizeof(struct sctp_assocparams)) {
- error = EINVAL;
- break;
- }
- sasoc = mtod(m, struct sctp_assocparams *);
- stcb = NULL;
+ SCTP_CHECK_AND_CAST(sasoc, optval, struct sctp_assocparams, *optsize);
+ SCTP_FIND_STCB(inp, stcb, sasoc->sasoc_assoc_id);
- if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
- SCTP_INP_RLOCK(inp);
- stcb = LIST_FIRST(&inp->sctp_asoc_list);
- if (stcb) {
-
- SCTP_TCB_LOCK(stcb);
- }
- SCTP_INP_RUNLOCK(inp);
- } else if (sasoc->sasoc_assoc_id) {
- stcb = sctp_findassociation_ep_asocid(inp,
- sasoc->sasoc_assoc_id, 1);
- if (stcb == NULL) {
- error = ENOENT;
- break;
- }
- } else {
- stcb = NULL;
- }
if (stcb) {
sasoc->sasoc_asocmaxrxt = stcb->asoc.max_send_times;
sasoc->sasoc_number_peer_destinations = stcb->asoc.numnets;
@@ -2859,53 +2664,39 @@ sctp_optsget(struct socket *so,
sasoc->sasoc_cookie_life = inp->sctp_ep.def_cookie_life;
SCTP_INP_RUNLOCK(inp);
}
- SCTP_BUF_LEN(m) = sizeof(*sasoc);
+ *optsize = sizeof(*sasoc);
}
break;
case SCTP_DEFAULT_SEND_PARAM:
{
struct sctp_sndrcvinfo *s_info;
- if (SCTP_BUF_LEN(m) != sizeof(struct sctp_sndrcvinfo)) {
- error = EINVAL;
- break;
- }
- s_info = mtod(m, struct sctp_sndrcvinfo *);
- if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
+ SCTP_CHECK_AND_CAST(s_info, optval, struct sctp_sndrcvinfo, *optsize);
+ SCTP_FIND_STCB(inp, stcb, s_info->sinfo_assoc_id);
+
+ if (stcb) {
+ *s_info = stcb->asoc.def_send;
+ SCTP_TCB_UNLOCK(stcb);
+ } else {
SCTP_INP_RLOCK(inp);
- stcb = LIST_FIRST(&inp->sctp_asoc_list);
- if (stcb)
- SCTP_TCB_LOCK(stcb);
+ *s_info = inp->def_send;
SCTP_INP_RUNLOCK(inp);
- } else
- stcb = sctp_findassociation_ep_asocid(inp, s_info->sinfo_assoc_id, 1);
-
- if (stcb == NULL) {
- error = ENOENT;
- break;
}
- /* Copy it out */
- *s_info = stcb->asoc.def_send;
- SCTP_TCB_UNLOCK(stcb);
- SCTP_BUF_LEN(m) = sizeof(*s_info);
+ *optsize = sizeof(*s_info);
}
break;
case SCTP_INITMSG:
{
struct sctp_initmsg *sinit;
- if ((size_t)SCTP_BUF_LEN(m) < sizeof(struct sctp_initmsg)) {
- error = EINVAL;
- break;
- }
- sinit = mtod(m, struct sctp_initmsg *);
+ SCTP_CHECK_AND_CAST(sinit, optval, struct sctp_initmsg, *optsize);
SCTP_INP_RLOCK(inp);
sinit->sinit_num_ostreams = inp->sctp_ep.pre_open_stream_count;
sinit->sinit_max_instreams = inp->sctp_ep.max_open_streams_intome;
sinit->sinit_max_attempts = inp->sctp_ep.max_init_times;
sinit->sinit_max_init_timeo = inp->sctp_ep.initial_init_rto_max;
SCTP_INP_RUNLOCK(inp);
- SCTP_BUF_LEN(m) = sizeof(*sinit);
+ *optsize = sizeof(*sinit);
}
break;
case SCTP_PRIMARY_ADDR:
@@ -2913,45 +2704,18 @@ sctp_optsget(struct socket *so,
{
struct sctp_setprim *ssp;
- if ((size_t)SCTP_BUF_LEN(m) < sizeof(struct sctp_setprim)) {
- error = EINVAL;
- break;
- }
- ssp = mtod(m, struct sctp_setprim *);
- if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
- SCTP_INP_RLOCK(inp);
- stcb = LIST_FIRST(&inp->sctp_asoc_list);
- if (stcb)
- SCTP_TCB_LOCK(stcb);
- SCTP_INP_RUNLOCK(inp);
+ SCTP_CHECK_AND_CAST(ssp, optval, struct sctp_setprim, *optsize);
+ SCTP_FIND_STCB(inp, stcb, ssp->ssp_assoc_id);
+
+ if (stcb) {
+ /* simply copy out the sockaddr_storage... */
+ memcpy(&ssp->ssp_addr, &stcb->asoc.primary_destination->ro._l_addr,
+ ((struct sockaddr *)&stcb->asoc.primary_destination->ro._l_addr)->sa_len);
+ SCTP_TCB_UNLOCK(stcb);
} else {
- stcb = sctp_findassociation_ep_asocid(inp, ssp->ssp_assoc_id, 1);
- if (stcb == NULL) {
- /*
- * one last shot, try it by the
- * address in
- */
- struct sctp_nets *net;
-
- SCTP_INP_INCR_REF(inp);
- stcb = sctp_findassociation_ep_addr(&inp,
- (struct sockaddr *)&ssp->ssp_addr,
- &net, NULL, NULL);
- if (stcb == NULL) {
- SCTP_INP_DECR_REF(inp);
- }
- }
- if (stcb == NULL) {
- error = EINVAL;
- break;
- }
+ error = EINVAL;
}
- /* simply copy out the sockaddr_storage... */
- memcpy(&ssp->ssp_addr,
- &stcb->asoc.primary_destination->ro._l_addr,
- ((struct sockaddr *)&stcb->asoc.primary_destination->ro._l_addr)->sa_len);
- SCTP_TCB_UNLOCK(stcb);
- SCTP_BUF_LEN(m) = sizeof(*ssp);
+ *optsize = sizeof(*ssp);
}
break;
@@ -2962,22 +2726,19 @@ sctp_optsget(struct socket *so,
uint32_t size;
int i;
- if ((size_t)(SCTP_BUF_LEN(m)) < sizeof(*shmac)) {
- error = EINVAL;
- break;
- }
- shmac = mtod(m, struct sctp_hmacalgo *);
+ SCTP_CHECK_AND_CAST(shmac, optval, struct sctp_hmacalgo, *optsize);
+
SCTP_INP_RLOCK(inp);
hmaclist = inp->sctp_ep.local_hmacs;
if (hmaclist == NULL) {
/* no HMACs to return */
- SCTP_BUF_LEN(m) = sizeof(*shmac);
+ *optsize = sizeof(*shmac);
break;
}
/* is there room for all of the hmac ids? */
size = sizeof(*shmac) + (hmaclist->num_algo *
sizeof(shmac->shmac_idents[0]));
- if ((size_t)(SCTP_BUF_LEN(m)) < size) {
+ if ((size_t)(*optsize) < size) {
error = EINVAL;
SCTP_INP_RUNLOCK(inp);
break;
@@ -2986,36 +2747,17 @@ sctp_optsget(struct socket *so,
for (i = 0; i < hmaclist->num_algo; i++)
shmac->shmac_idents[i] = hmaclist->hmac[i];
SCTP_INP_RUNLOCK(inp);
- SCTP_BUF_LEN(m) = size;
+ *optsize = size;
break;
}
case SCTP_AUTH_ACTIVE_KEY:
{
struct sctp_authkeyid *scact;
- if ((size_t)(SCTP_BUF_LEN(m)) < sizeof(*scact)) {
- error = EINVAL;
- break;
- }
- scact = mtod(m, struct sctp_authkeyid *);
- if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
- /*
- * if one-to-one, get from the connected
- * assoc; else endpoint
- */
- SCTP_INP_RLOCK(inp);
- stcb = LIST_FIRST(&inp->sctp_asoc_list);
- if (stcb)
- SCTP_TCB_LOCK(stcb);
- SCTP_INP_RUNLOCK(inp);
- } else if (scact->scact_assoc_id) {
- stcb = sctp_findassociation_ep_asocid(inp, scact->scact_assoc_id, 1);
- if (stcb == NULL) {
- error = ENOENT;
- break;
- }
- }
- if (stcb != NULL) {
+ SCTP_CHECK_AND_CAST(scact, optval, struct sctp_authkeyid, *optsize);
+ SCTP_FIND_STCB(inp, stcb, scact->scact_assoc_id);
+
+ if (stcb) {
/* get the active key on the assoc */
scact->scact_keynumber = stcb->asoc.authinfo.assoc_keyid;
SCTP_TCB_UNLOCK(stcb);
@@ -3025,131 +2767,79 @@ sctp_optsget(struct socket *so,
scact->scact_keynumber = inp->sctp_ep.default_keyid;
SCTP_INP_RUNLOCK(inp);
}
- SCTP_BUF_LEN(m) = sizeof(*scact);
+ *optsize = sizeof(*scact);
break;
}
case SCTP_LOCAL_AUTH_CHUNKS:
{
struct sctp_authchunks *sac;
sctp_auth_chklist_t *chklist = NULL;
- int size = 0;
+ size_t size = 0;
- if ((size_t)(SCTP_BUF_LEN(m)) < sizeof(*sac)) {
- error = EINVAL;
- break;
- }
- sac = mtod(m, struct sctp_authchunks *);
- if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
- /*
- * if one-to-one, get from the connected
- * assoc; else endpoint
- */
- SCTP_INP_RLOCK(inp);
- stcb = LIST_FIRST(&inp->sctp_asoc_list);
- if (stcb != NULL)
- SCTP_TCB_LOCK(stcb);
- SCTP_INP_RUNLOCK(inp);
- } else if (sac->gauth_assoc_id) {
- stcb = sctp_findassociation_ep_asocid(inp, sac->gauth_assoc_id, 1);
- if (stcb == NULL) {
- error = ENOENT;
- break;
- }
- }
- if (stcb != NULL) {
+ SCTP_CHECK_AND_CAST(sac, optval, struct sctp_authchunks, *optsize);
+ SCTP_FIND_STCB(inp, stcb, sac->gauth_assoc_id);
+
+ if (stcb) {
/* get off the assoc */
chklist = stcb->asoc.local_auth_chunks;
- if (chklist == NULL) {
- error = EINVAL;
- SCTP_TCB_UNLOCK(stcb);
- break;
- }
/* is there enough space? */
size = sctp_auth_get_chklist_size(chklist);
- if ((size_t)SCTP_BUF_LEN(m) < (sizeof(struct sctp_authchunks) + size)) {
+ if (*optsize < (sizeof(struct sctp_authchunks) + size)) {
error = EINVAL;
- SCTP_TCB_UNLOCK(stcb);
- break;
+ } else {
+ /* copy in the chunks */
+ sctp_serialize_auth_chunks(chklist, sac->gauth_chunks);
}
- /* copy in the chunks */
- sctp_serialize_auth_chunks(chklist, sac->gauth_chunks);
SCTP_TCB_UNLOCK(stcb);
} else {
/* get off the endpoint */
SCTP_INP_RLOCK(inp);
chklist = inp->sctp_ep.local_auth_chunks;
- if (chklist == NULL) {
- error = EINVAL;
- SCTP_INP_RUNLOCK(inp);
- break;
- }
/* is there enough space? */
size = sctp_auth_get_chklist_size(chklist);
- if ((size_t)SCTP_BUF_LEN(m) < (sizeof(struct sctp_authchunks) + size)) {
+ if (*optsize < (sizeof(struct sctp_authchunks) + size)) {
error = EINVAL;
- SCTP_INP_RUNLOCK(inp);
- break;
+ } else {
+ /* copy in the chunks */
+ sctp_serialize_auth_chunks(chklist, sac->gauth_chunks);
}
- /* copy in the chunks */
- sctp_serialize_auth_chunks(chklist, sac->gauth_chunks);
SCTP_INP_RUNLOCK(inp);
}
- SCTP_BUF_LEN(m) = sizeof(struct sctp_authchunks) + size;
+ *optsize = sizeof(struct sctp_authchunks) + size;
break;
}
case SCTP_PEER_AUTH_CHUNKS:
{
struct sctp_authchunks *sac;
sctp_auth_chklist_t *chklist = NULL;
- int size = 0;
+ size_t size = 0;
- if ((size_t)(SCTP_BUF_LEN(m)) < sizeof(*sac)) {
- error = EINVAL;
- break;
- }
- sac = mtod(m, struct sctp_authchunks *);
- if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
- /*
- * if one-to-one, get from the connected
- * assoc, else endpoint
- */
- SCTP_INP_RLOCK(inp);
- stcb = LIST_FIRST(&inp->sctp_asoc_list);
- if (stcb != NULL)
- SCTP_TCB_LOCK(stcb);
- SCTP_INP_RUNLOCK(inp);
- } else if (sac->gauth_assoc_id) {
- stcb = sctp_findassociation_ep_asocid(inp, sac->gauth_assoc_id, 1);
- }
- if (stcb == NULL) {
- error = ENOENT;
- break;
- }
- /* get off the assoc */
- chklist = stcb->asoc.peer_auth_chunks;
- if (chklist == NULL) {
- error = EINVAL;
- SCTP_TCB_UNLOCK(stcb);
- break;
- }
- /* is there enough space? */
- size = sctp_auth_get_chklist_size(chklist);
- if ((size_t)SCTP_BUF_LEN(m) < (sizeof(struct sctp_authchunks) + size)) {
- error = EINVAL;
+ SCTP_CHECK_AND_CAST(sac, optval, struct sctp_authchunks, *optsize);
+ SCTP_FIND_STCB(inp, stcb, sac->gauth_assoc_id);
+
+ if (stcb) {
+ /* get off the assoc */
+ chklist = stcb->asoc.peer_auth_chunks;
+ /* is there enough space? */
+ size = sctp_auth_get_chklist_size(chklist);
+ if (*optsize < (sizeof(struct sctp_authchunks) + size)) {
+ error = EINVAL;
+ } else {
+ /* copy in the chunks */
+ sctp_serialize_auth_chunks(chklist, sac->gauth_chunks);
+ }
SCTP_TCB_UNLOCK(stcb);
- break;
+ } else {
+ error = ENOENT;
}
- /* copy in the chunks */
- sctp_serialize_auth_chunks(chklist, sac->gauth_chunks);
- SCTP_TCB_UNLOCK(stcb);
- SCTP_BUF_LEN(m) = sizeof(struct sctp_authchunks) + size;
+ *optsize = sizeof(struct sctp_authchunks) + size;
break;
}
default:
error = ENOPROTOOPT;
- SCTP_BUF_LEN(m) = 0;
+ *optsize = 0;
break;
} /* end switch (sopt->sopt_name) */
return (error);
@@ -3157,31 +2847,23 @@ sctp_optsget(struct socket *so,
static int
-sctp_optsset(struct socket *so,
- int opt,
- struct mbuf **mp,
- struct thread *p
-)
+sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
+ void *p)
{
- int error, *mopt, set_opt;
- struct mbuf *m;
-
+ int error, set_opt;
+ uint32_t *mopt;
struct sctp_tcb *stcb = NULL;
struct sctp_inpcb *inp;
- if (mp == NULL) {
+ if (optval == NULL) {
return (EINVAL);
}
- m = *mp;
- if (m == NULL)
- return (EINVAL);
-
inp = (struct sctp_inpcb *)so->so_pcb;
if (inp == 0)
return EINVAL;
error = 0;
- switch (opt) {
+ switch (optname) {
case SCTP_NODELAY:
case SCTP_AUTOCLOSE:
case SCTP_AUTO_ASCONF:
@@ -3190,15 +2872,11 @@ sctp_optsset(struct socket *so,
case SCTP_USE_EXT_RCVINFO:
case SCTP_I_WANT_MAPPED_V4_ADDR:
/* copy in the option value */
- if ((size_t)SCTP_BUF_LEN(m) < sizeof(int)) {
- error = EINVAL;
- break;
- }
- mopt = mtod(m, int *);
+ SCTP_CHECK_AND_CAST(mopt, optval, uint32_t, optsize);
set_opt = 0;
if (error)
break;
- switch (opt) {
+ switch (optname) {
case SCTP_DISABLE_FRAGMENTS:
set_opt = SCTP_PCB_FLAGS_NO_FRAGMENT;
break;
@@ -3240,25 +2918,19 @@ sctp_optsset(struct socket *so,
break;
case SCTP_PARTIAL_DELIVERY_POINT:
{
- if ((size_t)SCTP_BUF_LEN(m) < sizeof(unsigned int)) {
- error = EINVAL;
- break;
- }
- inp->partial_delivery_point = *mtod(m, unsigned int *);
- SCTP_BUF_LEN(m) = sizeof(unsigned int);
+ uint32_t *value;
+
+ SCTP_CHECK_AND_CAST(value, optval, uint32_t, optsize);
+ inp->partial_delivery_point = *value;
}
break;
case SCTP_FRAGMENT_INTERLEAVE:
/* not yet until we re-write sctp_recvmsg() */
{
- int on_off;
+ uint32_t *on_off;
- if ((size_t)SCTP_BUF_LEN(m) < sizeof(int)) {
- error = EINVAL;
- break;
- }
- on_off = *(mtod(m, int *));
- if (on_off) {
+ SCTP_CHECK_AND_CAST(on_off, optval, uint32_t, optsize);
+ if (*on_off) {
sctp_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE);
} else {
sctp_feature_off(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE);
@@ -3269,37 +2941,18 @@ sctp_optsset(struct socket *so,
{
struct sctp_assoc_value *av;
- if ((size_t)SCTP_BUF_LEN(m) < sizeof(struct sctp_assoc_value)) {
- error = EINVAL;
- break;
- }
- av = mtod(m, struct sctp_assoc_value *);
- stcb = sctp_findassociation_ep_asocid(inp, av->assoc_id, 1);
- if (stcb == NULL) {
- error = ENOTCONN;
- } else {
- if (sctp_cmt_on_off) {
+ SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
+ if (sctp_cmt_on_off) {
+ SCTP_FIND_STCB(inp, stcb, av->assoc_id);
+ if (stcb) {
stcb->asoc.sctp_cmt_on_off = (uint8_t) av->assoc_value;
+ SCTP_TCB_UNLOCK(stcb);
} else {
- if ((stcb->asoc.sctp_cmt_on_off) && (av->assoc_value == 0)) {
- stcb->asoc.sctp_cmt_on_off = 0;
- } else {
- error = EACCES;
- }
+ error = ENOTCONN;
}
- SCTP_TCB_UNLOCK(stcb);
- }
- }
- break;
- case SCTP_CMT_USE_DAC:
- {
- if ((size_t)SCTP_BUF_LEN(m) < sizeof(unsigned int)) {
- error = EINVAL;
- break;
+ } else {
+ error = ENOPROTOOPT;
}
- sctp_cmt_sockopt_use_dac = *mtod(m, unsigned int *);
- if (sctp_cmt_sockopt_use_dac != 0)
- sctp_cmt_sockopt_use_dac = 1;
}
break;
case SCTP_CLR_STAT_LOG:
@@ -3311,24 +2964,18 @@ sctp_optsset(struct socket *so,
break;
case SCTP_CONTEXT:
{
-
struct sctp_assoc_value *av;
- if ((size_t)SCTP_BUF_LEN(m) < sizeof(struct sctp_assoc_value)) {
- error = EINVAL;
- break;
- }
- av = mtod(m, struct sctp_assoc_value *);
- if (av->assoc_id) {
- stcb = sctp_findassociation_ep_asocid(inp, av->assoc_id, 1);
- if (stcb == NULL) {
- error = ENOTCONN;
- } else {
- stcb->asoc.context = av->assoc_value;
- SCTP_TCB_UNLOCK(stcb);
- }
+ SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
+ SCTP_FIND_STCB(inp, stcb, av->assoc_id);
+
+ if (stcb) {
+ stcb->asoc.context = av->assoc_value;
+ SCTP_TCB_UNLOCK(stcb);
} else {
+ SCTP_INP_WLOCK(inp);
inp->sctp_context = av->assoc_value;
+ SCTP_INP_WUNLOCK(inp);
}
}
break;
@@ -3336,53 +2983,29 @@ sctp_optsset(struct socket *so,
{
struct sctp_assoc_value *tm;
- if ((size_t)SCTP_BUF_LEN(m) < sizeof(struct sctp_assoc_value)) {
- error = EINVAL;
- break;
- }
- tm = mtod(m, struct sctp_assoc_value *);
+ SCTP_CHECK_AND_CAST(tm, optval, struct sctp_assoc_value, optsize);
+ SCTP_FIND_STCB(inp, stcb, tm->assoc_id);
- if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
+ if (stcb) {
+ stcb->asoc.delayed_ack = tm->assoc_value;
+ SCTP_TCB_UNLOCK(stcb);
+ } else {
SCTP_INP_WLOCK(inp);
- stcb = LIST_FIRST(&inp->sctp_asoc_list);
- if (stcb) {
- SCTP_TCB_LOCK(stcb);
- stcb->asoc.delayed_ack = tm->assoc_value;
- SCTP_TCB_UNLOCK(stcb);
- } else {
- inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_RECV] = MSEC_TO_TICKS(tm->assoc_value);
- }
+ inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_RECV] = MSEC_TO_TICKS(tm->assoc_value);
SCTP_INP_WUNLOCK(inp);
- } else {
- if (tm->assoc_id) {
- stcb = sctp_findassociation_ep_asocid(inp, tm->assoc_id, 1);
- if (stcb == NULL) {
- error = ENOTCONN;
- } else {
- stcb->asoc.delayed_ack = tm->assoc_value;
- SCTP_TCB_UNLOCK(stcb);
- }
- } else {
- SCTP_INP_WLOCK(inp);
- inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_RECV] = MSEC_TO_TICKS(tm->assoc_value);
- SCTP_INP_WUNLOCK(inp);
- }
}
+ break;
}
- break;
-
case SCTP_AUTH_CHUNK:
{
struct sctp_authchunk *sauth;
- if ((size_t)SCTP_BUF_LEN(m) < sizeof(*sauth)) {
- error = EINVAL;
- break;
- }
- sauth = mtod(m, struct sctp_authchunk *);
- if (sctp_auth_add_chunk(sauth->sauth_chunk,
- inp->sctp_ep.local_auth_chunks))
+ SCTP_CHECK_AND_CAST(sauth, optval, struct sctp_authchunk, optsize);
+
+ SCTP_INP_WLOCK(inp);
+ if (sctp_auth_add_chunk(sauth->sauth_chunk, inp->sctp_ep.local_auth_chunks))
error = EINVAL;
+ SCTP_INP_WUNLOCK(inp);
break;
}
case SCTP_AUTH_KEY:
@@ -3391,32 +3014,13 @@ sctp_optsset(struct socket *so,
struct sctp_keyhead *shared_keys;
sctp_sharedkey_t *shared_key;
sctp_key_t *key = NULL;
- int size;
+ size_t size;
- size = SCTP_BUF_LEN(m) - sizeof(*sca);
- if (size < 0) {
- error = EINVAL;
- break;
- }
- sca = mtod(m, struct sctp_authkey *);
- if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
- /*
- * if one-to-one, set it on the connected
- * assoc; else endpoint
- */
- SCTP_INP_RLOCK(inp);
- stcb = LIST_FIRST(&inp->sctp_asoc_list);
- if (stcb)
- SCTP_TCB_LOCK(stcb);
- SCTP_INP_RUNLOCK(inp);
- } else if (sca->sca_assoc_id) {
- stcb = sctp_findassociation_ep_asocid(inp, sca->sca_assoc_id, 1);
- if (stcb == NULL) {
- error = ENOENT;
- break;
- }
- }
- if (stcb != NULL) {
+ SCTP_CHECK_AND_CAST(sca, optval, struct sctp_authkey, optsize);
+ SCTP_FIND_STCB(inp, stcb, sca->sca_assoc_id)
+ size = optsize - sizeof(*sca);
+
+ if (stcb) {
/* set it on the assoc */
shared_keys = &stcb->asoc.shared_keys;
/* clear the cached keys for this key id */
@@ -3445,7 +3049,7 @@ sctp_optsset(struct socket *so,
sctp_insert_sharedkey(shared_keys, shared_key);
SCTP_TCB_UNLOCK(stcb);
} else {
- /* ste it on the endpoint */
+ /* set it on the endpoint */
SCTP_INP_WLOCK(inp);
shared_keys = &inp->sctp_ep.shared_keys;
/*
@@ -3484,15 +3088,10 @@ sctp_optsset(struct socket *so,
struct sctp_hmacalgo *shmac;
sctp_hmaclist_t *hmaclist;
uint32_t hmacid;
- int size, i;
+ size_t size, i;
- size = SCTP_BUF_LEN(m) - sizeof(*shmac);
- if (size < 0) {
- error = EINVAL;
- break;
- }
- shmac = mtod(m, struct sctp_hmacalgo *);
- size = size / sizeof(shmac->shmac_idents[0]);
+ SCTP_CHECK_AND_CAST(shmac, optval, struct sctp_hmacalgo, optsize);
+ size = (optsize - sizeof(*shmac)) / sizeof(shmac->shmac_idents[0]);
hmaclist = sctp_alloc_hmaclist(size);
if (hmaclist == NULL) {
error = ENOMEM;
@@ -3520,30 +3119,11 @@ sctp_optsset(struct socket *so,
{
struct sctp_authkeyid *scact;
- if ((size_t)SCTP_BUF_LEN(m) < sizeof(*scact)) {
- error = EINVAL;
- break;
- }
- scact = mtod(m, struct sctp_authkeyid *);
- if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
- /*
- * if one-to-one, set it on the connected
- * assoc; else endpoint
- */
- SCTP_INP_RLOCK(inp);
- stcb = LIST_FIRST(&inp->sctp_asoc_list);
- if (stcb)
- SCTP_TCB_LOCK(stcb);
- SCTP_INP_RUNLOCK(inp);
- } else if (scact->scact_assoc_id) {
- stcb = sctp_findassociation_ep_asocid(inp, scact->scact_assoc_id, 1);
- if (stcb == NULL) {
- error = ENOENT;
- break;
- }
- }
+ SCTP_CHECK_AND_CAST(scact, optval, struct sctp_authkeyid, optsize);
+ SCTP_FIND_STCB(inp, stcb, scact->scact_assoc_id);
+
/* set the active key on the right place */
- if (stcb != NULL) {
+ if (stcb) {
/* set the active key on the assoc */
if (sctp_auth_setactivekey(stcb, scact->scact_keynumber))
error = EINVAL;
@@ -3561,30 +3141,11 @@ sctp_optsset(struct socket *so,
{
struct sctp_authkeyid *scdel;
- if ((size_t)SCTP_BUF_LEN(m) < sizeof(*scdel)) {
- error = EINVAL;
- break;
- }
- scdel = mtod(m, struct sctp_authkeyid *);
- if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
- /*
- * if one-to-one, delete from the connected
- * assoc; else endpoint
- */
- SCTP_INP_RLOCK(inp);
- stcb = LIST_FIRST(&inp->sctp_asoc_list);
- if (stcb)
- SCTP_TCB_LOCK(stcb);
- SCTP_INP_RUNLOCK(inp);
- } else if (scdel->scact_assoc_id) {
- stcb = sctp_findassociation_ep_asocid(inp, scdel->scact_assoc_id, 1);
- if (stcb == NULL) {
- error = ENOENT;
- break;
- }
- }
+ SCTP_CHECK_AND_CAST(scdel, optval, struct sctp_authkeyid, optsize);
+ SCTP_FIND_STCB(inp, stcb, scdel->scact_assoc_id);
+
/* delete the key from the right place */
- if (stcb != NULL) {
+ if (stcb) {
if (sctp_delete_sharedkey(stcb, scdel->scact_keynumber))
error = EINVAL;
SCTP_TCB_UNLOCK(stcb);
@@ -3603,20 +3164,9 @@ sctp_optsset(struct socket *so,
uint8_t send_in = 0, send_tsn = 0, send_out = 0;
int i;
- if ((size_t)SCTP_BUF_LEN(m) < sizeof(struct sctp_stream_reset)) {
- error = EINVAL;
- break;
- }
- strrst = mtod(m, struct sctp_stream_reset *);
+ SCTP_CHECK_AND_CAST(strrst, optval, struct sctp_stream_reset, optsize);
+ SCTP_FIND_STCB(inp, stcb, strrst->strrst_assoc_id);
- if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
- SCTP_INP_RLOCK(inp);
- stcb = LIST_FIRST(&inp->sctp_asoc_list);
- if (stcb)
- SCTP_TCB_LOCK(stcb);
- SCTP_INP_RUNLOCK(inp);
- } else
- stcb = sctp_findassociation_ep_asocid(inp, strrst->strrst_assoc_id, 1);
if (stcb == NULL) {
error = ENOENT;
break;
@@ -3676,23 +3226,23 @@ sctp_optsset(struct socket *so,
sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_STRRST_REQ);
SCTP_TCB_UNLOCK(stcb);
-
}
break;
+
case SCTP_CONNECT_X:
- if ((size_t)SCTP_BUF_LEN(m) < (sizeof(int) + sizeof(struct sockaddr_in))) {
+ if (optsize < (sizeof(int) + sizeof(struct sockaddr_in))) {
error = EINVAL;
break;
}
- error = sctp_do_connect_x(so, inp, m, p, 0);
+ error = sctp_do_connect_x(so, inp, optval, optsize, p, 0);
break;
case SCTP_CONNECT_X_DELAYED:
- if ((size_t)SCTP_BUF_LEN(m) < (sizeof(int) + sizeof(struct sockaddr_in))) {
+ if (optsize < (sizeof(int) + sizeof(struct sockaddr_in))) {
error = EINVAL;
break;
}
- error = sctp_do_connect_x(so, inp, m, p, 1);
+ error = sctp_do_connect_x(so, inp, optval, optsize, p, 1);
break;
case SCTP_CONNECT_X_COMPLETE:
@@ -3700,11 +3250,9 @@ sctp_optsset(struct socket *so,
struct sockaddr *sa;
struct sctp_nets *net;
- if ((size_t)SCTP_BUF_LEN(m) < sizeof(struct sockaddr_in)) {
- error = EINVAL;
- break;
- }
- sa = mtod(m, struct sockaddr *);
+ /* FIXME MT: check correct? */
+ SCTP_CHECK_AND_CAST(sa, optval, struct sockaddr, optsize);
+
/* find tcb */
if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
SCTP_INP_RLOCK(inp);
@@ -3715,6 +3263,13 @@ sctp_optsset(struct socket *so,
}
SCTP_INP_RUNLOCK(inp);
} else {
+ /*
+ * We increment here since
+ * sctp_findassociation_ep_addr() wil do a
+ * decrement if it finds the stcb as long as
+ * the locked tcb (last argument) is NOT a
+ * TCB.. aka NULL.
+ */
SCTP_INP_INCR_REF(inp);
stcb = sctp_findassociation_ep_addr(&inp, sa, &net, NULL, NULL);
if (stcb == NULL) {
@@ -3747,8 +3302,9 @@ sctp_optsset(struct socket *so,
{
uint8_t *burst;
+ SCTP_CHECK_AND_CAST(burst, optval, uint8_t, optsize);
+
SCTP_INP_WLOCK(inp);
- burst = mtod(m, uint8_t *);
if (*burst) {
inp->sctp_ep.max_burst = *burst;
}
@@ -3760,52 +3316,30 @@ sctp_optsset(struct socket *so,
uint32_t *segsize;
int ovh;
+ SCTP_CHECK_AND_CAST(segsize, optval, uint32_t, optsize);
+
if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
ovh = SCTP_MED_OVERHEAD;
} else {
ovh = SCTP_MED_V4_OVERHEAD;
}
- segsize = mtod(m, uint32_t *);
- if (*segsize < 1) {
- error = EINVAL;
- break;
- }
SCTP_INP_WLOCK(inp);
- inp->sctp_frag_point = (*segsize + ovh);
- SCTP_INP_WUNLOCK(inp);
- }
- break;
- case SCTP_SET_DEBUG_LEVEL:
-#ifdef SCTP_DEBUG
- {
- uint32_t *level;
-
- if ((size_t)SCTP_BUF_LEN(m) < sizeof(uint32_t)) {
+ /* FIXME MT: Why is this not allowed? */
+ if (*segsize) {
+ inp->sctp_frag_point = (*segsize + ovh);
+ } else {
error = EINVAL;
- break;
}
- level = mtod(m, uint32_t *);
- error = 0;
- sctp_debug_on = (*level & (SCTP_DEBUG_ALL |
- SCTP_DEBUG_NOISY));
- printf("SETTING DEBUG LEVEL to %x\n",
- (uint32_t) sctp_debug_on);
-
+ SCTP_INP_WUNLOCK(inp);
}
-#else
- error = EOPNOTSUPP;
-#endif /* SCTP_DEBUG */
break;
case SCTP_EVENTS:
{
struct sctp_event_subscribe *events;
- if ((size_t)SCTP_BUF_LEN(m) < sizeof(struct sctp_event_subscribe)) {
- error = EINVAL;
- break;
- }
+ SCTP_CHECK_AND_CAST(events, optval, struct sctp_event_subscribe, optsize);
+
SCTP_INP_WLOCK(inp);
- events = mtod(m, struct sctp_event_subscribe *);
if (events->sctp_data_io_event) {
sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVDATAIOEVNT);
} else {
@@ -3873,69 +3407,43 @@ sctp_optsset(struct socket *so,
{
struct sctp_setadaptation *adap_bits;
- if ((size_t)SCTP_BUF_LEN(m) < sizeof(struct sctp_setadaptation)) {
- error = EINVAL;
- break;
- }
+ SCTP_CHECK_AND_CAST(adap_bits, optval, struct sctp_setadaptation, optsize);
SCTP_INP_WLOCK(inp);
- adap_bits = mtod(m, struct sctp_setadaptation *);
inp->sctp_ep.adaptation_layer_indicator = adap_bits->ssb_adaptation_ind;
SCTP_INP_WUNLOCK(inp);
}
break;
+#ifdef SCTP_DEBUG
case SCTP_SET_INITIAL_DBG_SEQ:
{
uint32_t *vvv;
- if ((size_t)SCTP_BUF_LEN(m) < sizeof(uint32_t)) {
- error = EINVAL;
- break;
- }
+ SCTP_CHECK_AND_CAST(vvv, optval, uint32_t, optsize);
SCTP_INP_WLOCK(inp);
- vvv = mtod(m, uint32_t *);
inp->sctp_ep.initial_sequence_debug = *vvv;
SCTP_INP_WUNLOCK(inp);
}
break;
+#endif
case SCTP_DEFAULT_SEND_PARAM:
{
struct sctp_sndrcvinfo *s_info;
- if (SCTP_BUF_LEN(m) != sizeof(struct sctp_sndrcvinfo)) {
- error = EINVAL;
- break;
- }
- s_info = mtod(m, struct sctp_sndrcvinfo *);
+ SCTP_CHECK_AND_CAST(s_info, optval, struct sctp_sndrcvinfo, optsize);
+ SCTP_FIND_STCB(inp, stcb, s_info->sinfo_assoc_id);
- if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
- SCTP_INP_RLOCK(inp);
- stcb = LIST_FIRST(&inp->sctp_asoc_list);
- if (stcb)
- SCTP_TCB_LOCK(stcb);
- SCTP_INP_RUNLOCK(inp);
- } else {
- if (s_info->sinfo_assoc_id) {
- stcb = sctp_findassociation_ep_asocid(inp, s_info->sinfo_assoc_id, 1);
+ if (stcb) {
+ if (s_info->sinfo_stream <= stcb->asoc.streamoutcnt) {
+ stcb->asoc.def_send = *s_info;
} else {
- stcb = NULL;
+ error = EINVAL;
}
- }
- if ((s_info->sinfo_assoc_id == 0) &&
- (stcb == NULL)) {
- inp->def_send = *s_info;
- } else if (stcb == NULL) {
- error = ENOENT;
- break;
- }
- /* Validate things */
- if (s_info->sinfo_stream > stcb->asoc.streamoutcnt) {
SCTP_TCB_UNLOCK(stcb);
- error = EINVAL;
- break;
+ } else {
+ SCTP_INP_WLOCK(inp);
+ inp->def_send = *s_info;
+ SCTP_INP_WUNLOCK(inp);
}
- /* Copy it in */
- stcb->asoc.def_send = *s_info;
- SCTP_TCB_UNLOCK(stcb);
}
break;
case SCTP_PEER_ADDR_PARAMS:
@@ -3944,52 +3452,29 @@ sctp_optsset(struct socket *so,
struct sctp_paddrparams *paddrp;
struct sctp_nets *net;
- if ((size_t)SCTP_BUF_LEN(m) < sizeof(struct sctp_paddrparams)) {
- error = EINVAL;
- break;
- }
- paddrp = mtod(m, struct sctp_paddrparams *);
+ SCTP_CHECK_AND_CAST(paddrp, optval, struct sctp_paddrparams, optsize);
+ SCTP_FIND_STCB(inp, stcb, paddrp->spp_assoc_id);
net = NULL;
- if (paddrp->spp_assoc_id) {
- if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
- SCTP_INP_RLOCK(inp);
- stcb = LIST_FIRST(&inp->sctp_asoc_list);
- if (stcb) {
- SCTP_TCB_LOCK(stcb);
- net = sctp_findnet(stcb, (struct sockaddr *)&paddrp->spp_address);
- }
- SCTP_INP_RUNLOCK(inp);
- } else {
- stcb = sctp_findassociation_ep_asocid(inp, paddrp->spp_assoc_id, 1);
- }
+ if (stcb) {
+ net = sctp_findnet(stcb, (struct sockaddr *)&paddrp->spp_address);
+ } else {
+ /*
+ * We increment here since
+ * sctp_findassociation_ep_addr() wil do a
+ * decrement if it finds the stcb as long as
+ * the locked tcb (last argument) is NOT a
+ * TCB.. aka NULL.
+ */
+ SCTP_INP_INCR_REF(inp);
+ stcb = sctp_findassociation_ep_addr(&inp,
+ (struct sockaddr *)&paddrp->spp_address,
+ &net, NULL, NULL);
if (stcb == NULL) {
- error = ENOENT;
- break;
- }
- }
- if ((stcb == NULL) &&
- ((((struct sockaddr *)&paddrp->spp_address)->sa_family == AF_INET) ||
- (((struct sockaddr *)&paddrp->spp_address)->sa_family == AF_INET6))) {
- /* Lookup via address */
- if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
- SCTP_INP_RLOCK(inp);
- stcb = LIST_FIRST(&inp->sctp_asoc_list);
- if (stcb) {
- SCTP_TCB_LOCK(stcb);
- net = sctp_findnet(stcb,
- (struct sockaddr *)&paddrp->spp_address);
- }
- SCTP_INP_RUNLOCK(inp);
- } else {
- SCTP_INP_INCR_REF(inp);
- stcb = sctp_findassociation_ep_addr(&inp,
- (struct sockaddr *)&paddrp->spp_address,
- &net, NULL, NULL);
- if (stcb == NULL) {
- SCTP_INP_DECR_REF(inp);
- }
+ SCTP_INP_DECR_REF(inp);
}
}
+
+
if (stcb) {
/************************TCB SPECIFIC SET ******************/
/* sack delay first */
@@ -4137,12 +3622,19 @@ sctp_optsset(struct socket *so,
{
struct sctp_rtoinfo *srto;
- if ((size_t)SCTP_BUF_LEN(m) < sizeof(struct sctp_rtoinfo)) {
- error = EINVAL;
- break;
- }
- srto = mtod(m, struct sctp_rtoinfo *);
- if (srto->srto_assoc_id == 0) {
+ SCTP_CHECK_AND_CAST(srto, optval, struct sctp_rtoinfo, optsize);
+ SCTP_FIND_STCB(inp, stcb, srto->srto_assoc_id);
+
+ if (stcb) {
+ /* Set in ms we hope :-) */
+ if (srto->srto_initial > 10)
+ stcb->asoc.initial_rto = srto->srto_initial;
+ if (srto->srto_max > 10)
+ stcb->asoc.maxrto = srto->srto_max;
+ if (srto->srto_min > 10)
+ stcb->asoc.minrto = srto->srto_min;
+ SCTP_TCB_UNLOCK(stcb);
+ } else {
SCTP_INP_WLOCK(inp);
/*
* If we have a null asoc, its default for
@@ -4155,56 +3647,16 @@ sctp_optsset(struct socket *so,
if (srto->srto_min > 10)
inp->sctp_ep.sctp_minrto = srto->srto_min;
SCTP_INP_WUNLOCK(inp);
- break;
- }
- if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
- SCTP_INP_RLOCK(inp);
- stcb = LIST_FIRST(&inp->sctp_asoc_list);
- if (stcb)
- SCTP_TCB_LOCK(stcb);
- SCTP_INP_RUNLOCK(inp);
- } else
- stcb = sctp_findassociation_ep_asocid(inp, srto->srto_assoc_id, 1);
- if (stcb == NULL) {
- error = EINVAL;
- break;
}
- /* Set in ms we hope :-) */
- if (srto->srto_initial > 10)
- stcb->asoc.initial_rto = srto->srto_initial;
- if (srto->srto_max > 10)
- stcb->asoc.maxrto = srto->srto_max;
- if (srto->srto_min > 10)
- stcb->asoc.minrto = srto->srto_min;
- SCTP_TCB_UNLOCK(stcb);
}
break;
case SCTP_ASSOCINFO:
{
struct sctp_assocparams *sasoc;
- if ((size_t)SCTP_BUF_LEN(m) < sizeof(struct sctp_assocparams)) {
- error = EINVAL;
- break;
- }
- sasoc = mtod(m, struct sctp_assocparams *);
- if (sasoc->sasoc_assoc_id) {
- if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
- SCTP_INP_RLOCK(inp);
- stcb = LIST_FIRST(&inp->sctp_asoc_list);
- if (stcb)
- SCTP_TCB_LOCK(stcb);
- SCTP_INP_RUNLOCK(inp);
- } else
- stcb = sctp_findassociation_ep_asocid(inp,
- sasoc->sasoc_assoc_id, 1);
- if (stcb == NULL) {
- error = ENOENT;
- break;
- }
- } else {
- stcb = NULL;
- }
+ SCTP_CHECK_AND_CAST(sasoc, optval, struct sctp_assocparams, optsize);
+ SCTP_FIND_STCB(inp, stcb, sasoc->sasoc_assoc_id);
+
if (stcb) {
if (sasoc->sasoc_asocmaxrxt)
stcb->asoc.max_send_times = sasoc->sasoc_asocmaxrxt;
@@ -4231,11 +3683,7 @@ sctp_optsset(struct socket *so,
{
struct sctp_initmsg *sinit;
- if ((size_t)SCTP_BUF_LEN(m) < sizeof(struct sctp_initmsg)) {
- error = EINVAL;
- break;
- }
- sinit = mtod(m, struct sctp_initmsg *);
+ SCTP_CHECK_AND_CAST(sinit, optval, struct sctp_initmsg, optsize);
SCTP_INP_WLOCK(inp);
if (sinit->sinit_num_ostreams)
inp->sctp_ep.pre_open_stream_count = sinit->sinit_num_ostreams;
@@ -4251,6 +3699,7 @@ sctp_optsset(struct socket *so,
* We must be at least a 100ms (we set in
* ticks)
*/
+ /* FIXME MT: What is this? */
inp->sctp_ep.initial_init_rto_max = sinit->sinit_max_init_timeo;
SCTP_INP_WUNLOCK(inp);
}
@@ -4260,61 +3709,47 @@ sctp_optsset(struct socket *so,
struct sctp_setprim *spa;
struct sctp_nets *net, *lnet;
- if ((size_t)SCTP_BUF_LEN(m) < sizeof(struct sctp_setprim)) {
- error = EINVAL;
- break;
- }
- spa = mtod(m, struct sctp_setprim *);
+ SCTP_CHECK_AND_CAST(spa, optval, struct sctp_setprim, optsize);
+ SCTP_FIND_STCB(inp, stcb, spa->ssp_assoc_id);
- if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
- SCTP_INP_RLOCK(inp);
- stcb = LIST_FIRST(&inp->sctp_asoc_list);
- if (stcb) {
- SCTP_TCB_LOCK(stcb);
- } else {
- error = EINVAL;
- break;
- }
- SCTP_INP_RUNLOCK(inp);
- } else
- stcb = sctp_findassociation_ep_asocid(inp, spa->ssp_assoc_id, 1);
- if (stcb == NULL) {
- /* One last shot */
+ net = NULL;
+ if (stcb) {
+ net = sctp_findnet(stcb, (struct sockaddr *)&spa->ssp_addr);
+ } else {
+ /*
+ * We increment here since
+ * sctp_findassociation_ep_addr() wil do a
+ * decrement if it finds the stcb as long as
+ * the locked tcb (last argument) is NOT a
+ * TCB.. aka NULL.
+ */
SCTP_INP_INCR_REF(inp);
stcb = sctp_findassociation_ep_addr(&inp,
(struct sockaddr *)&spa->ssp_addr,
&net, NULL, NULL);
if (stcb == NULL) {
SCTP_INP_DECR_REF(inp);
- error = EINVAL;
- break;
- }
- } else {
- /*
- * find the net, associd or connected lookup
- * type
- */
- net = sctp_findnet(stcb, (struct sockaddr *)&spa->ssp_addr);
- if (net == NULL) {
- SCTP_TCB_UNLOCK(stcb);
- error = EINVAL;
- break;
}
}
- if ((net != stcb->asoc.primary_destination) &&
- (!(net->dest_state & SCTP_ADDR_UNCONFIRMED))) {
- /* Ok we need to set it */
- lnet = stcb->asoc.primary_destination;
- if (sctp_set_primary_addr(stcb,
- (struct sockaddr *)NULL,
- net) == 0) {
- if (net->dest_state & SCTP_ADDR_SWITCH_PRIMARY) {
- net->dest_state |= SCTP_ADDR_DOUBLE_SWITCH;
+
+ if ((stcb) && (net)) {
+ if ((net != stcb->asoc.primary_destination) &&
+ (!(net->dest_state & SCTP_ADDR_UNCONFIRMED))) {
+ /* Ok we need to set it */
+ lnet = stcb->asoc.primary_destination;
+ if (sctp_set_primary_addr(stcb, (struct sockaddr *)NULL, net) == 0) {
+ if (net->dest_state & SCTP_ADDR_SWITCH_PRIMARY) {
+ net->dest_state |= SCTP_ADDR_DOUBLE_SWITCH;
+ }
+ net->dest_state |= SCTP_ADDR_SWITCH_PRIMARY;
}
- net->dest_state |= SCTP_ADDR_SWITCH_PRIMARY;
}
+ } else {
+ error = EINVAL;
+ }
+ if (stcb) {
+ SCTP_TCB_UNLOCK(stcb);
}
- SCTP_TCB_UNLOCK(stcb);
}
break;
@@ -4322,26 +3757,14 @@ sctp_optsset(struct socket *so,
{
struct sctp_setpeerprim *sspp;
- if ((size_t)SCTP_BUF_LEN(m) < sizeof(struct sctp_setpeerprim)) {
- error = EINVAL;
- break;
- }
- sspp = mtod(m, struct sctp_setpeerprim *);
-
+ SCTP_CHECK_AND_CAST(sspp, optval, struct sctp_setpeerprim, optsize);
+ SCTP_FIND_STCB(inp, stcb, sspp->sspp_assoc_id);
- if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
- SCTP_INP_RLOCK(inp);
- stcb = LIST_FIRST(&inp->sctp_asoc_list);
- if (stcb)
- SCTP_TCB_UNLOCK(stcb);
- SCTP_INP_RUNLOCK(inp);
- } else
- stcb = sctp_findassociation_ep_asocid(inp, sspp->sspp_assoc_id, 1);
- if (stcb == NULL) {
- error = EINVAL;
- break;
- }
- if (sctp_set_primary_ip_address_sa(stcb, (struct sockaddr *)&sspp->sspp_addr) != 0) {
+ if (stcb) {
+ if (sctp_set_primary_ip_address_sa(stcb, (struct sockaddr *)&sspp->sspp_addr) != 0) {
+ error = EINVAL;
+ }
+ } else {
error = EINVAL;
}
SCTP_TCB_UNLOCK(stcb);
@@ -4353,16 +3776,13 @@ sctp_optsset(struct socket *so,
struct sockaddr *addr_touse;
struct sockaddr_in sin;
+ SCTP_CHECK_AND_CAST(addrs, optval, struct sctp_getaddresses, optsize);
+
/* see if we're bound all already! */
if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
error = EINVAL;
break;
}
- if ((size_t)SCTP_BUF_LEN(m) < sizeof(struct sctp_getaddresses)) {
- error = EINVAL;
- break;
- }
- addrs = mtod(m, struct sctp_getaddresses *);
addr_touse = addrs->addr;
if (addrs->addr->sa_family == AF_INET6) {
struct sockaddr_in6 *sin6;
@@ -4429,16 +3849,12 @@ sctp_optsset(struct socket *so,
struct sockaddr *addr_touse;
struct sockaddr_in sin;
+ SCTP_CHECK_AND_CAST(addrs, optval, struct sctp_getaddresses, optsize);
/* see if we're bound all already! */
if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
error = EINVAL;
break;
}
- if ((size_t)SCTP_BUF_LEN(m) < sizeof(struct sctp_getaddresses)) {
- error = EINVAL;
- break;
- }
- addrs = mtod(m, struct sctp_getaddresses *);
addr_touse = addrs->addr;
if (addrs->addr->sa_family == AF_INET6) {
struct sockaddr_in6 *sin6;
@@ -4480,9 +3896,11 @@ extern int sctp_chatty_mbuf;
int
sctp_ctloutput(struct socket *so, struct sockopt *sopt)
{
- struct mbuf *m = NULL;
+ void *optval = NULL;
+ size_t optsize = 0;
struct sctp_inpcb *inp;
- int error;
+ void *p;
+ int error = 0;
inp = (struct sctp_inpcb *)so->so_pcb;
if (inp == 0) {
@@ -4499,40 +3917,31 @@ sctp_ctloutput(struct socket *so, struct sockopt *sopt)
error = ip_ctloutput(so, sopt);
return (error);
}
- if (sopt->sopt_valsize) {
- if (sopt->sopt_valsize < MLEN) {
- m = sctp_get_mbuf_for_msg(1, 0, M_WAIT, 1, MT_DATA);
- } else {
- m = sctp_get_mbuf_for_msg(sopt->sopt_valsize, 0, M_WAIT, 1, MT_DATA);
- }
- if (m == NULL) {
- sctp_m_freem(m);
+ optsize = sopt->sopt_valsize;
+ if (optsize) {
+ SCTP_MALLOC(optval, void *, optsize, "SCTPSockOpt");
+ if (optval == NULL) {
return (ENOBUFS);
}
- if (sopt->sopt_valsize > M_TRAILINGSPACE(m)) {
- /* Limit to actual size gotten */
- sopt->sopt_valsize = M_TRAILINGSPACE(m);
- }
- error = sooptcopyin(sopt, mtod(m, caddr_t), sopt->sopt_valsize,
- sopt->sopt_valsize);
+ error = sooptcopyin(sopt, optval, optsize, optsize);
if (error) {
- (void)sctp_m_free(m);
+ SCTP_FREE(optval);
goto out;
}
- SCTP_BUF_LEN(m) = sopt->sopt_valsize;
}
+ p = (void *)sopt->sopt_td;
if (sopt->sopt_dir == SOPT_SET) {
- error = sctp_optsset(so, sopt->sopt_name, &m, sopt->sopt_td);
+ error = sctp_setopt(so, sopt->sopt_name, optval, optsize, p);
} else if (sopt->sopt_dir == SOPT_GET) {
- error = sctp_optsget(so, sopt->sopt_name, &m, sopt->sopt_td);
+ error = sctp_getopt(so, sopt->sopt_name, optval, &optsize, p);
} else {
error = EINVAL;
}
- if ((error == 0) && (m != NULL)) {
- error = sooptcopyout(sopt, mtod(m, caddr_t), SCTP_BUF_LEN(m));
- sctp_m_freem(m);
- } else if (m != NULL) {
- sctp_m_freem(m);
+ if ((error == 0) && (optval != NULL)) {
+ error = sooptcopyout(sopt, optval, optsize);
+ SCTP_FREE(optval);
+ } else if (optval != NULL) {
+ SCTP_FREE(optval);
}
out:
return (error);
@@ -4596,8 +4005,9 @@ sctp_connect(struct socket *so, struct sockaddr *addr, struct thread *p)
SCTP_INP_RUNLOCK(inp);
} else {
/*
- * Raise the count a second time, since on sucess
- * f-a-ep_addr will decrement it.
+ * We increment here since sctp_findassociation_ep_addr()
+ * wil do a decrement if it finds the stcb as long as the
+ * locked tcb (last argument) is NOT a TCB.. aka NULL.
*/
SCTP_INP_INCR_REF(inp);
stcb = sctp_findassociation_ep_addr(&inp, addr, NULL, NULL, NULL);
@@ -4677,12 +4087,13 @@ sctp_listen(struct socket *so, int backlog, struct thread *p)
}
if (inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) {
/* We must do a bind. */
+ SOCK_UNLOCK(so);
SCTP_INP_RUNLOCK(inp);
if ((error = sctp_inpcb_bind(so, NULL, p))) {
/* bind error, probably perm */
- SOCK_UNLOCK(so);
return (error);
}
+ SOCK_LOCK(so);
} else {
SCTP_INP_RUNLOCK(inp);
}
@@ -4712,7 +4123,6 @@ sctp_accept(struct socket *so, struct sockaddr **addr)
int error;
-
inp = (struct sctp_inpcb *)so->so_pcb;
if (inp == 0) {
diff --git a/sys/netinet/sctp_var.h b/sys/netinet/sctp_var.h
index 8cfe411..5463673 100644
--- a/sys/netinet/sctp_var.h
+++ b/sys/netinet/sctp_var.h
@@ -36,7 +36,7 @@ __FBSDID("$FreeBSD$");
#ifndef _NETINET_SCTP_VAR_H_
#define _NETINET_SCTP_VAR_H_
-#include <sys/socketvar.h>
+
#include <netinet/sctp_uio.h>
/* SCTP Kernel structures */
@@ -250,77 +250,75 @@ extern uint32_t sctp_system_free_resc_limit;
*/
#define sctp_free_a_readq(_stcb, _readq) { \
- SCTP_ZONE_FREE(sctppcbinfo.ipi_zone_readq, (_readq)); \
- SCTP_DECR_READQ_COUNT(); \
+ SCTP_ZONE_FREE(sctppcbinfo.ipi_zone_readq, (_readq)); \
+ SCTP_DECR_READQ_COUNT(); \
}
#define sctp_alloc_a_readq(_stcb, _readq) { \
- (_readq) = (struct sctp_queued_to_read *)SCTP_ZONE_GET(sctppcbinfo.ipi_zone_readq); \
+ (_readq) = SCTP_ZONE_GET(sctppcbinfo.ipi_zone_readq, struct sctp_queued_to_read); \
if ((_readq)) { \
SCTP_INCR_READQ_COUNT(); \
} \
}
-
-
#define sctp_free_a_strmoq(_stcb, _strmoq) { \
- if (((_stcb)->asoc.free_strmoq_cnt > sctp_asoc_free_resc_limit) || \
- (sctppcbinfo.ipi_free_strmoq > sctp_system_free_resc_limit)) { \
+ if (((_stcb)->asoc.free_strmoq_cnt > sctp_asoc_free_resc_limit) || \
+ (sctppcbinfo.ipi_free_strmoq > sctp_system_free_resc_limit)) { \
SCTP_ZONE_FREE(sctppcbinfo.ipi_zone_strmoq, (_strmoq)); \
SCTP_DECR_STRMOQ_COUNT(); \
- } else { \
+ } else { \
TAILQ_INSERT_TAIL(&(_stcb)->asoc.free_strmoq, (_strmoq), next); \
- (_stcb)->asoc.free_strmoq_cnt++; \
- atomic_add_int(&sctppcbinfo.ipi_free_strmoq, 1); \
- } \
+ (_stcb)->asoc.free_strmoq_cnt++; \
+ atomic_add_int(&sctppcbinfo.ipi_free_strmoq, 1); \
+ } \
}
#define sctp_alloc_a_strmoq(_stcb, _strmoq) { \
- if(TAILQ_EMPTY(&(_stcb)->asoc.free_strmoq)) { \
- (_strmoq) = (struct sctp_stream_queue_pending *)SCTP_ZONE_GET(sctppcbinfo.ipi_zone_strmoq); \
- if ((_strmoq)) { \
- SCTP_INCR_STRMOQ_COUNT(); \
+ if (TAILQ_EMPTY(&(_stcb)->asoc.free_strmoq)) { \
+ (_strmoq) = SCTP_ZONE_GET(sctppcbinfo.ipi_zone_strmoq, struct sctp_stream_queue_pending); \
+ if ((_strmoq)) { \
+ SCTP_INCR_STRMOQ_COUNT(); \
+ } \
+ } else { \
+ (_strmoq) = TAILQ_FIRST(&(_stcb)->asoc.free_strmoq); \
+ TAILQ_REMOVE(&(_stcb)->asoc.free_strmoq, (_strmoq), next); \
+ atomic_subtract_int(&sctppcbinfo.ipi_free_strmoq, 1); \
+ (_stcb)->asoc.free_strmoq_cnt--; \
} \
- } else { \
- (_strmoq) = TAILQ_FIRST(&(_stcb)->asoc.free_strmoq); \
- TAILQ_REMOVE(&(_stcb)->asoc.free_strmoq, (_strmoq), next); \
- atomic_subtract_int(&sctppcbinfo.ipi_free_strmoq, 1); \
- (_stcb)->asoc.free_strmoq_cnt--; \
- } \
}
#define sctp_free_a_chunk(_stcb, _chk) { \
- if (((_stcb)->asoc.free_chunk_cnt > sctp_asoc_free_resc_limit) || \
- (sctppcbinfo.ipi_free_chunks > sctp_system_free_resc_limit)) { \
+ if (((_stcb)->asoc.free_chunk_cnt > sctp_asoc_free_resc_limit) || \
+ (sctppcbinfo.ipi_free_chunks > sctp_system_free_resc_limit)) { \
SCTP_ZONE_FREE(sctppcbinfo.ipi_zone_chunk, (_chk)); \
SCTP_DECR_CHK_COUNT(); \
- } else { \
+ } else { \
TAILQ_INSERT_TAIL(&(_stcb)->asoc.free_chunks, (_chk), sctp_next); \
- (_stcb)->asoc.free_chunk_cnt++; \
- atomic_add_int(&sctppcbinfo.ipi_free_chunks, 1); \
- } \
+ (_stcb)->asoc.free_chunk_cnt++; \
+ atomic_add_int(&sctppcbinfo.ipi_free_chunks, 1); \
+ } \
}
#define sctp_alloc_a_chunk(_stcb, _chk) { \
- if(TAILQ_EMPTY(&(_stcb)->asoc.free_chunks)) { \
- (_chk) = (struct sctp_tmit_chunk *)SCTP_ZONE_GET(sctppcbinfo.ipi_zone_chunk); \
- if ((_chk)) { \
- SCTP_INCR_CHK_COUNT(); \
+ if (TAILQ_EMPTY(&(_stcb)->asoc.free_chunks)) { \
+ (_chk) = SCTP_ZONE_GET(sctppcbinfo.ipi_zone_chunk, struct sctp_tmit_chunk); \
+ if ((_chk)) { \
+ SCTP_INCR_CHK_COUNT(); \
+ } \
+ } else { \
+ (_chk) = TAILQ_FIRST(&(_stcb)->asoc.free_chunks); \
+ TAILQ_REMOVE(&(_stcb)->asoc.free_chunks, (_chk), sctp_next); \
+ atomic_subtract_int(&sctppcbinfo.ipi_free_chunks, 1); \
+ (_stcb)->asoc.free_chunk_cnt--; \
} \
- } else { \
- (_chk) = TAILQ_FIRST(&(_stcb)->asoc.free_chunks); \
- TAILQ_REMOVE(&(_stcb)->asoc.free_chunks, (_chk), sctp_next); \
- atomic_subtract_int(&sctppcbinfo.ipi_free_chunks, 1); \
- (_stcb)->asoc.free_chunk_cnt--; \
- } \
}
#define sctp_free_remote_addr(__net) { \
if ((__net)) { \
- if (atomic_fetchadd_int(&(__net)->ref_count, -1) == 1) { \
+ if (atomic_fetchadd_int(&(__net)->ref_count, -1) == 1) { \
SCTP_OS_TIMER_STOP(&(__net)->rxt_timer.timer); \
SCTP_OS_TIMER_STOP(&(__net)->pmtu_timer.timer); \
SCTP_OS_TIMER_STOP(&(__net)->fr_timer.timer); \
@@ -332,37 +330,37 @@ extern uint32_t sctp_system_free_resc_limit;
}
#define sctp_sbfree(ctl, stcb, sb, m) { \
- uint32_t val; \
- val = atomic_fetchadd_int(&(sb)->sb_cc,-(SCTP_BUF_LEN((m)))); \
- if(val < SCTP_BUF_LEN((m))) { \
- panic("sb_cc goes negative"); \
- } \
- val = atomic_fetchadd_int(&(sb)->sb_mbcnt,-(MSIZE)); \
- if(val < MSIZE) { \
- panic("sb_mbcnt goes negative"); \
- } \
- if (SCTP_BUF_IS_EXTENDED(m)) { \
- val = atomic_fetchadd_int(&(sb)->sb_mbcnt,-(SCTP_BUF_EXTEND_SIZE(m))); \
- if(val < SCTP_BUF_EXTEND_SIZE(m)) { \
- panic("sb_mbcnt goes negative2"); \
- } \
- } \
- if (((ctl)->do_not_ref_stcb == 0) && stcb) {\
- val = atomic_fetchadd_int(&(stcb)->asoc.sb_cc,-(SCTP_BUF_LEN((m)))); \
- if(val < SCTP_BUF_LEN((m))) {\
- panic("stcb->sb_cc goes negative"); \
- } \
- val = atomic_fetchadd_int(&(stcb)->asoc.sb_mbcnt,-(MSIZE)); \
- if(val < MSIZE) { \
- panic("asoc->mbcnt goes negative"); \
- } \
+ uint32_t val; \
+ val = atomic_fetchadd_int(&(sb)->sb_cc,-(SCTP_BUF_LEN((m)))); \
+ if (val < SCTP_BUF_LEN((m))) { \
+ panic("sb_cc goes negative"); \
+ } \
+ val = atomic_fetchadd_int(&(sb)->sb_mbcnt,-(MSIZE)); \
+ if (val < MSIZE) { \
+ panic("sb_mbcnt goes negative"); \
+ } \
+ if (SCTP_BUF_IS_EXTENDED(m)) { \
+ val = atomic_fetchadd_int(&(sb)->sb_mbcnt,-(SCTP_BUF_EXTEND_SIZE(m))); \
+ if (val < SCTP_BUF_EXTEND_SIZE(m)) { \
+ panic("sb_mbcnt goes negative2"); \
+ } \
+ } \
+ if (((ctl)->do_not_ref_stcb == 0) && stcb) {\
+ val = atomic_fetchadd_int(&(stcb)->asoc.sb_cc,-(SCTP_BUF_LEN((m)))); \
+ if (val < SCTP_BUF_LEN((m))) {\
+ panic("stcb->sb_cc goes negative"); \
+ } \
+ val = atomic_fetchadd_int(&(stcb)->asoc.sb_mbcnt,-(MSIZE)); \
+ if (val < MSIZE) { \
+ panic("asoc->mbcnt goes negative"); \
+ } \
if (SCTP_BUF_IS_EXTENDED(m)) { \
- val = atomic_fetchadd_int(&(stcb)->asoc.sb_mbcnt,-(SCTP_BUF_EXTEND_SIZE(m))); \
- if(val < SCTP_BUF_EXTEND_SIZE(m)) { \
+ val = atomic_fetchadd_int(&(stcb)->asoc.sb_mbcnt,-(SCTP_BUF_EXTEND_SIZE(m))); \
+ if (val < SCTP_BUF_EXTEND_SIZE(m)) { \
panic("assoc stcb->mbcnt would go negative"); \
- } \
- } \
- } \
+ } \
+ } \
+ } \
if (SCTP_BUF_TYPE(m) != MT_DATA && SCTP_BUF_TYPE(m) != MT_HEADER && \
SCTP_BUF_TYPE(m) != MT_OOBDATA) \
atomic_subtract_int(&(sb)->sb_ctl,SCTP_BUF_LEN((m))); \
@@ -374,12 +372,12 @@ extern uint32_t sctp_system_free_resc_limit;
atomic_add_int(&(sb)->sb_mbcnt, MSIZE); \
if (SCTP_BUF_IS_EXTENDED(m)) \
atomic_add_int(&(sb)->sb_mbcnt,SCTP_BUF_EXTEND_SIZE(m)); \
- if(stcb) { \
- atomic_add_int(&(stcb)->asoc.sb_cc,SCTP_BUF_LEN((m))); \
- atomic_add_int(&(stcb)->asoc.sb_mbcnt, MSIZE); \
- if (SCTP_BUF_IS_EXTENDED(m)) \
- atomic_add_int(&(stcb)->asoc.sb_mbcnt,SCTP_BUF_EXTEND_SIZE(m)); \
- } \
+ if (stcb) { \
+ atomic_add_int(&(stcb)->asoc.sb_cc,SCTP_BUF_LEN((m))); \
+ atomic_add_int(&(stcb)->asoc.sb_mbcnt, MSIZE); \
+ if (SCTP_BUF_IS_EXTENDED(m)) \
+ atomic_add_int(&(stcb)->asoc.sb_mbcnt,SCTP_BUF_EXTEND_SIZE(m)); \
+ } \
if (SCTP_BUF_TYPE(m) != MT_DATA && SCTP_BUF_TYPE(m) != MT_HEADER && \
SCTP_BUF_TYPE(m) != MT_OOBDATA) \
atomic_add_int(&(sb)->sb_ctl,SCTP_BUF_LEN((m))); \
@@ -399,14 +397,14 @@ extern uint32_t sctp_system_free_resc_limit;
}
#define sctp_mbuf_crush(data) do { \
- struct mbuf *_m; \
+ struct mbuf *_m; \
+ _m = (data); \
+ while(_m && (SCTP_BUF_LEN(_m) == 0)) { \
+ (data) = SCTP_BUF_NEXT(_m); \
+ SCTP_BUF_NEXT(_m) = NULL; \
+ sctp_m_free(_m); \
_m = (data); \
- while(_m && (SCTP_BUF_LEN(_m) == 0)) { \
- (data) = SCTP_BUF_NEXT(_m); \
- SCTP_BUF_NEXT(_m) = NULL; \
- sctp_m_free(_m); \
- _m = (data); \
- } \
+ } \
} while (0)
diff --git a/sys/netinet/sctputil.c b/sys/netinet/sctputil.c
index bbefbb6..8372ba6 100644
--- a/sys/netinet/sctputil.c
+++ b/sys/netinet/sctputil.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2001-2006, Cisco Systems, Inc. All rights reserved.
+ * Copyright (c) 2001-2007, Cisco Systems, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -1104,6 +1104,16 @@ sctp_init_asoc(struct sctp_inpcb *m, struct sctp_association *asoc,
asoc->authinfo.recv_key = NULL;
asoc->authinfo.recv_keyid = 0;
LIST_INIT(&asoc->shared_keys);
+ asoc->marked_retrans = 0;
+ asoc->timoinit = 0;
+ asoc->timodata = 0;
+ asoc->timosack = 0;
+ asoc->timoshutdown = 0;
+ asoc->timoheartbeat = 0;
+ asoc->timocookie = 0;
+ asoc->timoshutdownack = 0;
+ SCTP_GETTIME_TIMEVAL(&asoc->start_time);
+ SCTP_GETTIME_TIMEVAL(&asoc->discontinuity_time);
return (0);
}
@@ -1146,7 +1156,7 @@ sctp_handle_addr_wq(void)
return;
}
LIST_REMOVE(wi, sctp_nxt_addr);
- if (!LIST_EMPTY(&sctppcbinfo.addr_wq)) {
+ if (!SCTP_LIST_EMPTY(&sctppcbinfo.addr_wq)) {
sctp_timer_start(SCTP_TIMER_TYPE_ADDR_WQ,
(struct sctp_inpcb *)NULL,
(struct sctp_tcb *)NULL,
@@ -1281,6 +1291,7 @@ sctp_timeout_handler(void *t)
break;
case SCTP_TIMER_TYPE_SEND:
SCTP_STAT_INCR(sctps_timodata);
+ stcb->asoc.timodata++;
stcb->asoc.num_send_timers_up--;
if (stcb->asoc.num_send_timers_up < 0) {
stcb->asoc.num_send_timers_up = 0;
@@ -1312,6 +1323,7 @@ sctp_timeout_handler(void *t)
break;
case SCTP_TIMER_TYPE_INIT:
SCTP_STAT_INCR(sctps_timoinit);
+ stcb->asoc.timoinit++;
if (sctp_t1init_timer(inp, stcb, net)) {
/* no need to unlock on tcb its gone */
goto out_decr;
@@ -1321,6 +1333,7 @@ sctp_timeout_handler(void *t)
break;
case SCTP_TIMER_TYPE_RECV:
SCTP_STAT_INCR(sctps_timosack);
+ stcb->asoc.timosack++;
sctp_send_sack(stcb);
#ifdef SCTP_AUDITING_ENABLED
sctp_auditing(4, inp, stcb, net);
@@ -1333,6 +1346,7 @@ sctp_timeout_handler(void *t)
goto out_decr;
}
SCTP_STAT_INCR(sctps_timoshutdown);
+ stcb->asoc.timoshutdown++;
#ifdef SCTP_AUDITING_ENABLED
sctp_auditing(4, inp, stcb, net);
#endif
@@ -1344,6 +1358,7 @@ sctp_timeout_handler(void *t)
int cnt_of_unconf = 0;
SCTP_STAT_INCR(sctps_timoheartbeat);
+ stcb->asoc.timoheartbeat++;
TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
if ((net->dest_state & SCTP_ADDR_UNCONFIRMED) &&
(net->dest_state & SCTP_ADDR_REACHABLE)) {
@@ -1370,6 +1385,7 @@ sctp_timeout_handler(void *t)
goto out_decr;
}
SCTP_STAT_INCR(sctps_timocookie);
+ stcb->asoc.timocookie++;
#ifdef SCTP_AUDITING_ENABLED
sctp_auditing(4, inp, stcb, net);
#endif
@@ -1416,6 +1432,7 @@ sctp_timeout_handler(void *t)
goto out_decr;
}
SCTP_STAT_INCR(sctps_timoshutdownack);
+ stcb->asoc.timoshutdownack++;
#ifdef SCTP_AUDITING_ENABLED
sctp_auditing(4, inp, stcb, net);
#endif
@@ -2265,7 +2282,7 @@ sctp_mtu_size_reset(struct sctp_inpcb *inp,
/*
* given an association and starting time of the current RTT period return
- * RTO in number of usecs net should point to the current network
+ * RTO in number of msecs net should point to the current network
*/
uint32_t
sctp_calculate_rto(struct sctp_tcb *stcb,
@@ -2275,7 +2292,7 @@ sctp_calculate_rto(struct sctp_tcb *stcb,
{
/*
* given an association and the starting time of the current RTT
- * period (in value1/value2) return RTO in number of usecs.
+ * period (in value1/value2) return RTO in number of msecs.
*/
int calc_time = 0;
int o_calctime;
@@ -2610,7 +2627,15 @@ sctp_notify_peer_addr_change(struct sctp_tcb *stcb, uint32_t state,
if (sa->sa_family == AF_INET) {
memcpy(&spc->spc_aaddr, sa, sizeof(struct sockaddr_in));
} else {
+ struct sockaddr_in6 *sin6;
+
memcpy(&spc->spc_aaddr, sa, sizeof(struct sockaddr_in6));
+
+ /* recover scope_id for user */
+ sin6 = (struct sockaddr_in6 *)&spc->spc_aaddr;
+ if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr)) {
+ (void)sa6_recoverscope(sin6);
+ }
}
spc->spc_state = state;
spc->spc_error = error;
@@ -3458,7 +3483,6 @@ sctp_is_same_scope(struct sockaddr_in6 *addr1, struct sockaddr_in6 *addr2)
struct sockaddr_in6 *
sctp_recover_scope(struct sockaddr_in6 *addr, struct sockaddr_in6 *store)
{
-
/* check and strip embedded scope junk */
if (addr->sin6_family == AF_INET6) {
if (IN6_IS_SCOPE_LINKLOCAL(&addr->sin6_addr)) {
@@ -3468,7 +3492,9 @@ sctp_recover_scope(struct sockaddr_in6 *addr, struct sockaddr_in6 *store)
/* use the recovered scope */
addr = store;
}
+ } else {
/* else, return the original "to" addr */
+ in6_clearscope(&addr->sin6_addr);
}
}
}
@@ -4507,6 +4533,9 @@ found_one:
if (nxt->sinfo_flags & SCTP_UNORDERED) {
s_extra->next_flags |= SCTP_NEXT_MSG_IS_UNORDERED;
}
+ if (nxt->spec_flags & M_NOTIFICATION) {
+ s_extra->next_flags |= SCTP_NEXT_MSG_IS_NOTIFICATION;
+ }
s_extra->next_asocid = nxt->sinfo_assoc_id;
s_extra->next_length = nxt->length;
s_extra->next_ppid = nxt->sinfo_ppid;
@@ -4581,7 +4610,6 @@ found_one:
to6 = (struct sockaddr_in6 *)to;
sctp_recover_scope_mac(to6, (&lsa6));
-
}
#endif
}
diff --git a/sys/netinet/sctputil.h b/sys/netinet/sctputil.h
index b6dd2b4..82cd432 100644
--- a/sys/netinet/sctputil.h
+++ b/sys/netinet/sctputil.h
@@ -149,24 +149,24 @@ sctp_handle_ootb(struct mbuf *, int, int, struct sctphdr *,
int sctp_is_there_an_abort_here(struct mbuf *, int, uint32_t *);
uint32_t sctp_is_same_scope(struct sockaddr_in6 *, struct sockaddr_in6 *);
-struct sockaddr_in6 *
-sctp_recover_scope(struct sockaddr_in6 *,
- struct sockaddr_in6 *);
-
-
+struct sockaddr_in6 *
+ sctp_recover_scope(struct sockaddr_in6 *, struct sockaddr_in6 *);
#define sctp_recover_scope_mac(addr, store) do { \
- if ((addr->sin6_family == AF_INET6) && \
- (IN6_IS_SCOPE_LINKLOCAL(&addr->sin6_addr)) && \
- (addr->sin6_scope_id == 0)) { \
- *store = *addr; \
- if (!sa6_recoverscope(store)) { \
- addr = store; \
- } \
- } \
- } while (0)
-
+ if ((addr->sin6_family == AF_INET6) && \
+ (IN6_IS_SCOPE_LINKLOCAL(&addr->sin6_addr))) { \
+ *store = *addr; \
+ if (addr->sin6_scope_id == 0) { \
+ if (!sa6_recoverscope(store)) { \
+ addr = store; \
+ } \
+ } else { \
+ in6_clearscope(&addr->sin6_addr); \
+ addr = store; \
+ } \
+ } \
+} while (0)
int sctp_cmpaddr(struct sockaddr *, struct sockaddr *);
diff --git a/sys/netinet6/sctp6_usrreq.c b/sys/netinet6/sctp6_usrreq.c
index d7c3a3e..f08bf2e 100644
--- a/sys/netinet6/sctp6_usrreq.c
+++ b/sys/netinet6/sctp6_usrreq.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2001-2006, Cisco Systems, Inc. All rights reserved.
+ * Copyright (c) 2001-2007, Cisco Systems, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -715,7 +715,7 @@ sctp6_disconnect(struct socket *so)
}
SCTP_INP_RLOCK(inp);
if (inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) {
- if (LIST_EMPTY(&inp->sctp_asoc_list)) {
+ if (SCTP_LIST_EMPTY(&inp->sctp_asoc_list)) {
/* No connection */
SCTP_INP_RUNLOCK(inp);
return (ENOTCONN);
@@ -789,8 +789,11 @@ sctp6_disconnect(struct socket *so)
/* only send SHUTDOWN the first time */
sctp_send_shutdown(stcb, stcb->asoc.primary_destination);
sctp_chunk_output(stcb->sctp_ep, stcb, 1);
+ if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) ||
+ (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
+ SCTP_STAT_DECR_GAUGE32(sctps_currestab);
+ }
asoc->state = SCTP_STATE_SHUTDOWN_SENT;
- SCTP_STAT_DECR_GAUGE32(sctps_currestab);
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN,
stcb->sctp_ep, stcb,
asoc->primary_destination);
OpenPOWER on IntegriCloud