diff options
Diffstat (limited to 'sys/netinet')
-rw-r--r-- | sys/netinet/sctp_asconf.c | 8 | ||||
-rw-r--r-- | sys/netinet/sctp_auth.c | 99 | ||||
-rw-r--r-- | sys/netinet/sctp_auth.h | 41 | ||||
-rw-r--r-- | sys/netinet/sctp_constants.h | 32 | ||||
-rw-r--r-- | sys/netinet/sctp_crc32.c | 9 | ||||
-rw-r--r-- | sys/netinet/sctp_indata.c | 158 | ||||
-rw-r--r-- | sys/netinet/sctp_input.c | 60 | ||||
-rw-r--r-- | sys/netinet/sctp_os.h | 5 | ||||
-rw-r--r-- | sys/netinet/sctp_os_bsd.h | 35 | ||||
-rw-r--r-- | sys/netinet/sctp_output.c | 56 | ||||
-rw-r--r-- | sys/netinet/sctp_pcb.c | 77 | ||||
-rw-r--r-- | sys/netinet/sctp_peeloff.c | 2 | ||||
-rw-r--r-- | sys/netinet/sctp_structs.h | 32 | ||||
-rw-r--r-- | sys/netinet/sctp_timer.c | 13 | ||||
-rw-r--r-- | sys/netinet/sctp_uio.h | 52 | ||||
-rw-r--r-- | sys/netinet/sctp_usrreq.c | 1800 | ||||
-rw-r--r-- | sys/netinet/sctp_var.h | 160 | ||||
-rw-r--r-- | sys/netinet/sctputil.c | 40 | ||||
-rw-r--r-- | sys/netinet/sctputil.h | 30 |
19 files changed, 1175 insertions, 1534 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 *); |