Code from the hack-session known as the IETF (and a
bit of debugging afterwards): - Fix protection code for notification generation. - Decouple associd from vtag - Allow vtags to have less strigent requirements in non-uniqueness. o don't pre-hash them when you issue one in a cookie. o Allow duplicates and use addresses and ports to discriminate amongst the duplicates during lookup. - Add support for the NAT draft draft-ietf-behave-sctpnat-00, this is still experimental and needs more extensive testing with the Jason Butt ipfw changes. - Support for the SENDER_DRY event to get DTLS in OpenSSL working with a set of patches from Michael Tuexen (hopefully heading to OpenSSL soon). - Update the support of SCTP-AUTH by Peter Lei. - Use macros for refcounting. - Fix MTU for UDP encapsulation. - Fix reporting back of unsent data. - Update assoc send counter handling to be consistent with endpoint sent counter. - Fix a bug in PR-SCTP. - Fix so we only send another FWD-TSN when a SACK arrives IF and only if the adv-peer-ack point progressed. However we still make sure a timer is running if we do have an adv_peer_ack point. - Fix PR-SCTP bug where chunks were retransmitted if they are sent unreliable but not abandoned yet. With the help of: Michael Teuxen and Peter Lei :-) MFC after: 4 weeks
This commit is contained in:
parent
d27a975f72
commit
830d754d52
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=185694
@ -1,5 +1,5 @@
|
||||
/*-
|
||||
* Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved.
|
||||
* Copyright (c) 2001-2008, by 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:
|
||||
@ -111,6 +111,7 @@ struct sctp_paramhdr {
|
||||
/* explict EOR signalling */
|
||||
#define SCTP_EXPLICIT_EOR 0x0000001b
|
||||
#define SCTP_REUSE_PORT 0x0000001c /* rw */
|
||||
#define SCTP_AUTH_DEACTIVATE_KEY 0x0000001d
|
||||
|
||||
/*
|
||||
* read-only options
|
||||
@ -154,6 +155,8 @@ struct sctp_paramhdr {
|
||||
/* CMT ON/OFF socket option */
|
||||
#define SCTP_CMT_ON_OFF 0x00001200
|
||||
#define SCTP_CMT_USE_DAC 0x00001201
|
||||
/* EY - NR_SACK on/off socket option */
|
||||
#define SCTP_NR_SACK_ON_OFF 0x00001300
|
||||
/* JRS - Pluggable Congestion Control Socket option */
|
||||
#define SCTP_PLUGGABLE_CC 0x00001202
|
||||
|
||||
@ -293,11 +296,15 @@ struct sctp_paramhdr {
|
||||
#define SCTP_CAUSE_PROTOCOL_VIOLATION 0x000d
|
||||
|
||||
/* Error causes from RFC5061 */
|
||||
#define SCTP_CAUSE_DELETING_LAST_ADDR 0xa0
|
||||
#define SCTP_CAUSE_RESOURCE_SHORTAGE 0xa1
|
||||
#define SCTP_CAUSE_DELETING_SRC_ADDR 0xa2
|
||||
#define SCTP_CAUSE_ILLEGAL_ASCONF_ACK 0xa3
|
||||
#define SCTP_CAUSE_REQUEST_REFUSED 0xa4
|
||||
#define SCTP_CAUSE_DELETING_LAST_ADDR 0x00a0
|
||||
#define SCTP_CAUSE_RESOURCE_SHORTAGE 0x00a1
|
||||
#define SCTP_CAUSE_DELETING_SRC_ADDR 0x00a2
|
||||
#define SCTP_CAUSE_ILLEGAL_ASCONF_ACK 0x00a3
|
||||
#define SCTP_CAUSE_REQUEST_REFUSED 0x00a4
|
||||
|
||||
/* Error causes from nat-draft */
|
||||
#define SCTP_CAUSE_NAT_COLLIDING_STATE 0x00b0
|
||||
#define SCTP_CAUSE_NAT_MISSING_STATE 0x00b1
|
||||
|
||||
/* Error causes from RFC4895 */
|
||||
#define SCTP_CAUSE_UNSUPPORTED_HMACID 0x0105
|
||||
@ -364,6 +371,8 @@ struct sctp_error_unrecognized_chunk {
|
||||
#define SCTP_SHUTDOWN_COMPLETE 0x0e
|
||||
/* RFC4895 */
|
||||
#define SCTP_AUTHENTICATION 0x0f
|
||||
/* EY nr_sack chunk id*/
|
||||
#define SCTP_NR_SELECTIVE_ACK 0x10
|
||||
/************0x40 series ***********/
|
||||
/************0x80 series ***********/
|
||||
/* RFC5061 */
|
||||
@ -406,6 +415,9 @@ struct sctp_error_unrecognized_chunk {
|
||||
/* ECN Nonce: SACK Chunk Specific Flags */
|
||||
#define SCTP_SACK_NONCE_SUM 0x01
|
||||
|
||||
/* EY nr_sack all bit - All bit is the 2nd LSB of nr_sack chunk flags*/
|
||||
/* if All bit is set in an nr-sack chunk, then all nr gap acks gap acks*/
|
||||
#define SCTP_NR_SACK_ALL_BIT 0x02
|
||||
/* CMT DAC algorithm SACK flag */
|
||||
#define SCTP_SACK_CMT_DAC 0x80
|
||||
|
||||
@ -467,6 +479,7 @@ struct sctp_error_unrecognized_chunk {
|
||||
#define SCTP_PCB_FLAGS_NEEDS_MAPPED_V4 0x00800000
|
||||
#define SCTP_PCB_FLAGS_MULTIPLE_ASCONFS 0x01000000
|
||||
#define SCTP_PCB_FLAGS_PORTREUSE 0x02000000
|
||||
#define SCTP_PCB_FLAGS_DRYEVNT 0x04000000
|
||||
/*-
|
||||
* mobility_features parameters (by micchie).Note
|
||||
* these features are applied against the
|
||||
|
@ -761,6 +761,9 @@ sctp_handle_asconf(struct mbuf *m, unsigned int offset,
|
||||
m_result = sctp_process_asconf_set_primary(m, aph,
|
||||
stcb, error);
|
||||
break;
|
||||
case SCTP_NAT_VTAGS:
|
||||
SCTPDBG(SCTP_DEBUG_ASCONF1, "handle_asconf: sees a NAT VTAG state parameter\n");
|
||||
break;
|
||||
case SCTP_SUCCESS_REPORT:
|
||||
/* not valid in an ASCONF chunk */
|
||||
break;
|
||||
@ -1349,6 +1352,7 @@ sctp_asconf_queue_mgmt(struct sctp_tcb *stcb, struct sctp_ifa *ifa,
|
||||
SCTPDBG(SCTP_DEBUG_ASCONF1, "asconf_queue_mgmt: failed to get memory!\n");
|
||||
return (-1);
|
||||
}
|
||||
aa->special_del = 0;
|
||||
/* fill in asconf address parameter fields */
|
||||
/* top level elements are "networked" during send */
|
||||
aa->ap.aph.ph.param_type = type;
|
||||
@ -1555,6 +1559,7 @@ sctp_asconf_queue_sa_delete(struct sctp_tcb *stcb, struct sockaddr *sa)
|
||||
"sctp_asconf_queue_sa_delete: failed to get memory!\n");
|
||||
return (-1);
|
||||
}
|
||||
aa->special_del = 0;
|
||||
/* fill in asconf address parameter fields */
|
||||
/* top level elements are "networked" during send */
|
||||
aa->ap.aph.ph.param_type = SCTP_DEL_IP_ADDRESS;
|
||||
@ -2691,6 +2696,7 @@ sctp_compose_asconf(struct sctp_tcb *stcb, int *retlen, int addr_locked)
|
||||
* case)
|
||||
*/
|
||||
if (lookup_used == 0 &&
|
||||
(aa->special_del == 0) &&
|
||||
aa->ap.aph.ph.param_type == SCTP_DEL_IP_ADDRESS) {
|
||||
struct sctp_ipv6addr_param *lookup;
|
||||
uint16_t p_size, addr_size;
|
||||
@ -3234,3 +3240,195 @@ sctp_addr_mgmt_ep_sa(struct sctp_inpcb *inp, struct sockaddr *sa,
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
sctp_asconf_send_nat_state_update(struct sctp_tcb *stcb,
|
||||
struct sctp_nets *net)
|
||||
{
|
||||
struct sctp_asconf_addr *aa;
|
||||
struct sctp_ifa *sctp_ifap;
|
||||
struct sctp_asconf_tag_param *vtag;
|
||||
struct sockaddr_in *to;
|
||||
|
||||
#ifdef INET6
|
||||
struct sockaddr_in6 *to6;
|
||||
|
||||
#endif
|
||||
if (net == NULL) {
|
||||
SCTPDBG(SCTP_DEBUG_ASCONF1, "sctp_asconf_send_nat_state_update: Missing net\n");
|
||||
return;
|
||||
}
|
||||
if (stcb == NULL) {
|
||||
SCTPDBG(SCTP_DEBUG_ASCONF1, "sctp_asconf_send_nat_state_update: Missing stcb\n");
|
||||
return;
|
||||
}
|
||||
/*
|
||||
* Need to have in the asconf: - vtagparam(my_vtag/peer_vtag) -
|
||||
* add(0.0.0.0) - del(0.0.0.0) - Any global addresses add(addr)
|
||||
*/
|
||||
SCTP_MALLOC(aa, struct sctp_asconf_addr *, sizeof(*aa),
|
||||
SCTP_M_ASC_ADDR);
|
||||
if (aa == NULL) {
|
||||
/* didn't get memory */
|
||||
SCTPDBG(SCTP_DEBUG_ASCONF1,
|
||||
"sctp_asconf_send_nat_state_update: failed to get memory!\n");
|
||||
return;
|
||||
}
|
||||
aa->special_del = 0;
|
||||
/* fill in asconf address parameter fields */
|
||||
/* top level elements are "networked" during send */
|
||||
aa->ifa = NULL;
|
||||
aa->sent = 0; /* clear sent flag */
|
||||
vtag = (struct sctp_asconf_tag_param *)&aa->ap.aph;
|
||||
vtag->aph.ph.param_type = SCTP_NAT_VTAGS;
|
||||
vtag->aph.ph.param_length = sizeof(struct sctp_asconf_tag_param);
|
||||
vtag->local_vtag = htonl(stcb->asoc.my_vtag);
|
||||
vtag->remote_vtag = htonl(stcb->asoc.peer_vtag);
|
||||
TAILQ_INSERT_TAIL(&stcb->asoc.asconf_queue, aa, next);
|
||||
|
||||
SCTP_MALLOC(aa, struct sctp_asconf_addr *, sizeof(*aa),
|
||||
SCTP_M_ASC_ADDR);
|
||||
if (aa == NULL) {
|
||||
/* didn't get memory */
|
||||
SCTPDBG(SCTP_DEBUG_ASCONF1,
|
||||
"sctp_asconf_send_nat_state_update: failed to get memory!\n");
|
||||
return;
|
||||
}
|
||||
memset(aa, 0, sizeof(struct sctp_asconf_addr));
|
||||
/* fill in asconf address parameter fields */
|
||||
/* ADD(0.0.0.0) */
|
||||
if (net->ro._l_addr.sa.sa_family == AF_INET) {
|
||||
aa->ap.aph.ph.param_type = SCTP_ADD_IP_ADDRESS;
|
||||
aa->ap.aph.ph.param_length = sizeof(struct sctp_asconf_addrv4_param);
|
||||
aa->ap.addrp.ph.param_type = SCTP_IPV4_ADDRESS;
|
||||
aa->ap.addrp.ph.param_length = sizeof(struct sctp_ipv4addr_param);
|
||||
/* No need to add an address, we are using 0.0.0.0 */
|
||||
TAILQ_INSERT_TAIL(&stcb->asoc.asconf_queue, aa, next);
|
||||
}
|
||||
#ifdef INET6
|
||||
else if (net->ro._l_addr.sa.sa_family == AF_INET6) {
|
||||
aa->ap.aph.ph.param_type = SCTP_ADD_IP_ADDRESS;
|
||||
aa->ap.aph.ph.param_length = sizeof(struct sctp_asconf_addr_param);
|
||||
aa->ap.addrp.ph.param_type = SCTP_IPV6_ADDRESS;
|
||||
aa->ap.addrp.ph.param_length = sizeof(struct sctp_ipv6addr_param);
|
||||
/* No need to add an address, we are using 0.0.0.0 */
|
||||
TAILQ_INSERT_TAIL(&stcb->asoc.asconf_queue, aa, next);
|
||||
}
|
||||
#endif /* INET6 */
|
||||
SCTP_MALLOC(aa, struct sctp_asconf_addr *, sizeof(*aa),
|
||||
SCTP_M_ASC_ADDR);
|
||||
if (aa == NULL) {
|
||||
/* didn't get memory */
|
||||
SCTPDBG(SCTP_DEBUG_ASCONF1,
|
||||
"sctp_asconf_send_nat_state_update: failed to get memory!\n");
|
||||
return;
|
||||
}
|
||||
memset(aa, 0, sizeof(struct sctp_asconf_addr));
|
||||
/* fill in asconf address parameter fields */
|
||||
/* ADD(0.0.0.0) */
|
||||
if (net->ro._l_addr.sa.sa_family == AF_INET) {
|
||||
aa->ap.aph.ph.param_type = SCTP_ADD_IP_ADDRESS;
|
||||
aa->ap.aph.ph.param_length = sizeof(struct sctp_asconf_addrv4_param);
|
||||
aa->ap.addrp.ph.param_type = SCTP_IPV4_ADDRESS;
|
||||
aa->ap.addrp.ph.param_length = sizeof(struct sctp_ipv4addr_param);
|
||||
/* No need to add an address, we are using 0.0.0.0 */
|
||||
TAILQ_INSERT_TAIL(&stcb->asoc.asconf_queue, aa, next);
|
||||
}
|
||||
#ifdef INET6
|
||||
else if (net->ro._l_addr.sa.sa_family == AF_INET6) {
|
||||
aa->ap.aph.ph.param_type = SCTP_DEL_IP_ADDRESS;
|
||||
aa->ap.aph.ph.param_length = sizeof(struct sctp_asconf_addr_param);
|
||||
aa->ap.addrp.ph.param_type = SCTP_IPV6_ADDRESS;
|
||||
aa->ap.addrp.ph.param_length = sizeof(struct sctp_ipv6addr_param);
|
||||
/* No need to add an address, we are using 0.0.0.0 */
|
||||
TAILQ_INSERT_TAIL(&stcb->asoc.asconf_queue, aa, next);
|
||||
}
|
||||
#endif /* INET6 */
|
||||
/* Now we must hunt the addresses and add all global addresses */
|
||||
if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
|
||||
struct sctp_vrf *vrf = NULL;
|
||||
struct sctp_ifn *sctp_ifnp;
|
||||
uint32_t vrf_id;
|
||||
|
||||
vrf_id = stcb->sctp_ep->def_vrf_id;
|
||||
vrf = sctp_find_vrf(vrf_id);
|
||||
if (vrf == NULL) {
|
||||
goto skip_rest;
|
||||
}
|
||||
SCTP_IPI_ADDR_RLOCK();
|
||||
LIST_FOREACH(sctp_ifnp, &vrf->ifnlist, next_ifn) {
|
||||
LIST_FOREACH(sctp_ifap, &sctp_ifnp->ifalist, next_ifa) {
|
||||
if (sctp_ifap->address.sa.sa_family == AF_INET) {
|
||||
to = &sctp_ifap->address.sin;
|
||||
|
||||
if (IN4_ISPRIVATE_ADDRESS(&to->sin_addr)) {
|
||||
continue;
|
||||
}
|
||||
if (IN4_ISLOOPBACK_ADDRESS(&to->sin_addr)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
#ifdef INET6
|
||||
else if (sctp_ifap->address.sa.sa_family == AF_INET6) {
|
||||
to6 = &sctp_ifap->address.sin6;
|
||||
if (IN6_IS_ADDR_LOOPBACK(&to6->sin6_addr)) {
|
||||
continue;
|
||||
}
|
||||
if (IN6_IS_ADDR_LINKLOCAL(&to6->sin6_addr)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
sctp_asconf_queue_mgmt(stcb, sctp_ifap, SCTP_ADD_IP_ADDRESS);
|
||||
}
|
||||
}
|
||||
SCTP_IPI_ADDR_RUNLOCK();
|
||||
} else {
|
||||
struct sctp_laddr *laddr;
|
||||
|
||||
LIST_FOREACH(laddr, &stcb->sctp_ep->sctp_addr_list, sctp_nxt_addr) {
|
||||
if (laddr->ifa == NULL) {
|
||||
continue;
|
||||
}
|
||||
if (laddr->ifa->localifa_flags & SCTP_BEING_DELETED)
|
||||
/*
|
||||
* Address being deleted by the system, dont
|
||||
* list.
|
||||
*/
|
||||
continue;
|
||||
if (laddr->action == SCTP_DEL_IP_ADDRESS) {
|
||||
/*
|
||||
* Address being deleted on this ep don't
|
||||
* list.
|
||||
*/
|
||||
continue;
|
||||
}
|
||||
sctp_ifap = laddr->ifa;
|
||||
if (sctp_ifap->address.sa.sa_family == AF_INET) {
|
||||
to = &sctp_ifap->address.sin;
|
||||
|
||||
if (IN4_ISPRIVATE_ADDRESS(&to->sin_addr)) {
|
||||
continue;
|
||||
}
|
||||
if (IN4_ISLOOPBACK_ADDRESS(&to->sin_addr)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
#ifdef INET6
|
||||
else if (sctp_ifap->address.sa.sa_family == AF_INET6) {
|
||||
to6 = &sctp_ifap->address.sin6;
|
||||
if (IN6_IS_ADDR_LOOPBACK(&to6->sin6_addr)) {
|
||||
continue;
|
||||
}
|
||||
if (IN6_IS_ADDR_LINKLOCAL(&to6->sin6_addr)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
sctp_asconf_queue_mgmt(stcb, sctp_ifap, SCTP_ADD_IP_ADDRESS);
|
||||
}
|
||||
}
|
||||
skip_rest:
|
||||
/* Now we must send the asconf into the queue */
|
||||
sctp_send_asconf(stcb, net, 0);
|
||||
}
|
||||
|
@ -86,6 +86,10 @@ extern void
|
||||
extern void
|
||||
sctp_net_immediate_retrans(struct sctp_tcb *, struct sctp_nets *);
|
||||
|
||||
extern void
|
||||
sctp_asconf_send_nat_state_update(struct sctp_tcb *stcb,
|
||||
struct sctp_nets *net);
|
||||
|
||||
extern int
|
||||
sctp_is_addr_pending(struct sctp_tcb *, struct sctp_ifa *);
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*-
|
||||
* Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved.
|
||||
* Copyright (c) 2001-2008, by 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:
|
||||
@ -359,9 +359,11 @@ sctp_set_key(uint8_t * key, uint32_t keylen)
|
||||
return (new_key);
|
||||
}
|
||||
|
||||
/*
|
||||
/*-
|
||||
* given two keys of variable size, compute which key is "larger/smaller"
|
||||
* returns: 1 if key1 > key2 -1 if key1 < key2 0 if key1 = key2
|
||||
* returns: 1 if key1 > key2
|
||||
* -1 if key1 < key2
|
||||
* 0 if key1 = key2
|
||||
*/
|
||||
static int
|
||||
sctp_compare_key(sctp_key_t * key1, sctp_key_t * key2)
|
||||
@ -531,13 +533,18 @@ sctp_alloc_sharedkey(void)
|
||||
}
|
||||
new_key->keyid = 0;
|
||||
new_key->key = NULL;
|
||||
new_key->refcount = 1;
|
||||
new_key->deactivated = 0;
|
||||
return (new_key);
|
||||
}
|
||||
|
||||
void
|
||||
sctp_free_sharedkey(sctp_sharedkey_t * skey)
|
||||
{
|
||||
if (skey != NULL) {
|
||||
if (skey == NULL)
|
||||
return;
|
||||
|
||||
if (SCTP_DECREMENT_AND_CHECK_REFCOUNT(&skey->refcount)) {
|
||||
if (skey->key != NULL)
|
||||
sctp_free_key(skey->key);
|
||||
SCTP_FREE(skey, SCTP_M_AUTH_KY);
|
||||
@ -556,40 +563,93 @@ sctp_find_sharedkey(struct sctp_keyhead *shared_keys, uint16_t key_id)
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
void
|
||||
int
|
||||
sctp_insert_sharedkey(struct sctp_keyhead *shared_keys,
|
||||
sctp_sharedkey_t * new_skey)
|
||||
{
|
||||
sctp_sharedkey_t *skey;
|
||||
|
||||
if ((shared_keys == NULL) || (new_skey == NULL))
|
||||
return;
|
||||
return (EINVAL);
|
||||
|
||||
/* insert into an empty list? */
|
||||
if (SCTP_LIST_EMPTY(shared_keys)) {
|
||||
LIST_INSERT_HEAD(shared_keys, new_skey, next);
|
||||
return;
|
||||
return (0);
|
||||
}
|
||||
/* insert into the existing list, ordered by key id */
|
||||
LIST_FOREACH(skey, shared_keys, next) {
|
||||
if (new_skey->keyid < skey->keyid) {
|
||||
/* insert it before here */
|
||||
LIST_INSERT_BEFORE(skey, new_skey, next);
|
||||
return;
|
||||
return (0);
|
||||
} else if (new_skey->keyid == skey->keyid) {
|
||||
/* replace the existing key */
|
||||
/* verify this key *can* be replaced */
|
||||
if ((skey->deactivated) && (skey->refcount > 1)) {
|
||||
SCTPDBG(SCTP_DEBUG_AUTH1,
|
||||
"can't replace shared key id %u\n",
|
||||
new_skey->keyid);
|
||||
return (EBUSY);
|
||||
}
|
||||
SCTPDBG(SCTP_DEBUG_AUTH1,
|
||||
"replacing shared key id %u\n",
|
||||
new_skey->keyid);
|
||||
LIST_INSERT_BEFORE(skey, new_skey, next);
|
||||
LIST_REMOVE(skey, next);
|
||||
sctp_free_sharedkey(skey);
|
||||
return;
|
||||
return (0);
|
||||
}
|
||||
if (LIST_NEXT(skey, next) == NULL) {
|
||||
/* belongs at the end of the list */
|
||||
LIST_INSERT_AFTER(skey, new_skey, next);
|
||||
return;
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
/* shouldn't reach here */
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
sctp_auth_key_acquire(struct sctp_tcb *stcb, uint16_t key_id)
|
||||
{
|
||||
sctp_sharedkey_t *skey;
|
||||
|
||||
/* find the shared key */
|
||||
skey = sctp_find_sharedkey(&stcb->asoc.shared_keys, key_id);
|
||||
|
||||
/* bump the ref count */
|
||||
if (skey) {
|
||||
atomic_add_int(&skey->refcount, 1);
|
||||
SCTPDBG(SCTP_DEBUG_AUTH2,
|
||||
"%s: stcb %p key %u refcount acquire to %d\n",
|
||||
__FUNCTION__, stcb, key_id, skey->refcount);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
sctp_auth_key_release(struct sctp_tcb *stcb, uint16_t key_id)
|
||||
{
|
||||
sctp_sharedkey_t *skey;
|
||||
|
||||
/* find the shared key */
|
||||
skey = sctp_find_sharedkey(&stcb->asoc.shared_keys, key_id);
|
||||
|
||||
/* decrement the ref count */
|
||||
if (skey) {
|
||||
sctp_free_sharedkey(skey);
|
||||
SCTPDBG(SCTP_DEBUG_AUTH2,
|
||||
"%s: stcb %p key %u refcount release to %d\n",
|
||||
__FUNCTION__, stcb, key_id, skey->refcount);
|
||||
|
||||
/* see if a notification should be generated */
|
||||
if ((skey->refcount <= 1) && (skey->deactivated)) {
|
||||
/* notify ULP that key is no longer used */
|
||||
sctp_ulp_notify(SCTP_NOTIFY_AUTH_FREE_KEY, stcb,
|
||||
key_id, 0, SCTP_SO_NOT_LOCKED);
|
||||
SCTPDBG(SCTP_DEBUG_AUTH2,
|
||||
"%s: stcb %p key %u no longer used, %d\n",
|
||||
__FUNCTION__, stcb, key_id, skey->refcount);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -623,7 +683,7 @@ sctp_copy_skeylist(const struct sctp_keyhead *src, struct sctp_keyhead *dest)
|
||||
LIST_FOREACH(skey, src, next) {
|
||||
new_skey = sctp_copy_sharedkey(skey);
|
||||
if (new_skey != NULL) {
|
||||
sctp_insert_sharedkey(dest, new_skey);
|
||||
(void)sctp_insert_sharedkey(dest, new_skey);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
@ -727,9 +787,9 @@ sctp_default_supported_hmaclist(void)
|
||||
return (new_list);
|
||||
}
|
||||
|
||||
/*
|
||||
* HMAC algos are listed in priority/preference order find the best HMAC id
|
||||
* to use for the peer based on local support
|
||||
/*-
|
||||
* HMAC algos are listed in priority/preference order
|
||||
* find the best HMAC id to use for the peer based on local support
|
||||
*/
|
||||
uint16_t
|
||||
sctp_negotiate_hmacid(sctp_hmaclist_t * peer, sctp_hmaclist_t * local)
|
||||
@ -760,9 +820,9 @@ sctp_negotiate_hmacid(sctp_hmaclist_t * peer, sctp_hmaclist_t * local)
|
||||
return (SCTP_AUTH_HMAC_ID_RSVD);
|
||||
}
|
||||
|
||||
/*
|
||||
* serialize the HMAC algo list and return space used caller must guarantee
|
||||
* ptr has appropriate space
|
||||
/*-
|
||||
* serialize the HMAC algo list and return space used
|
||||
* caller must guarantee ptr has appropriate space
|
||||
*/
|
||||
int
|
||||
sctp_serialize_hmaclist(sctp_hmaclist_t * list, uint8_t * ptr)
|
||||
@ -994,7 +1054,7 @@ sctp_hmac_final(uint16_t hmac_algo, sctp_hash_context_t * ctx,
|
||||
} /* end switch */
|
||||
}
|
||||
|
||||
/*
|
||||
/*-
|
||||
* Keyed-Hashing for Message Authentication: FIPS 198 (RFC 2104)
|
||||
*
|
||||
* Compute the HMAC digest using the desired hash key, text, and HMAC
|
||||
@ -1142,9 +1202,10 @@ sctp_hmac_m(uint16_t hmac_algo, uint8_t * key, uint32_t keylen,
|
||||
return (digestlen);
|
||||
}
|
||||
|
||||
/*
|
||||
/*-
|
||||
* verify the HMAC digest using the desired hash key, text, and HMAC
|
||||
* algorithm. Returns -1 on error, 0 on success.
|
||||
* algorithm.
|
||||
* Returns -1 on error, 0 on success.
|
||||
*/
|
||||
int
|
||||
sctp_verify_hmac(uint16_t hmac_algo, uint8_t * key, uint32_t keylen,
|
||||
@ -1263,10 +1324,10 @@ sctp_auth_is_supported_hmac(sctp_hmaclist_t * list, uint16_t id)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* clear any cached key(s) if they match the given key id on an association
|
||||
* the cached key(s) will be recomputed and re-cached at next use. ASSUMES
|
||||
* TCB_LOCK is already held
|
||||
/*-
|
||||
* clear any cached key(s) if they match the given key id on an association.
|
||||
* the cached key(s) will be recomputed and re-cached at next use.
|
||||
* ASSUMES TCB_LOCK is already held
|
||||
*/
|
||||
void
|
||||
sctp_clear_cachedkeys(struct sctp_tcb *stcb, uint16_t keyid)
|
||||
@ -1284,9 +1345,10 @@ sctp_clear_cachedkeys(struct sctp_tcb *stcb, uint16_t keyid)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
/*-
|
||||
* clear any cached key(s) if they match the given key id for all assocs on
|
||||
* an association ASSUMES INP_WLOCK is already held
|
||||
* an endpoint.
|
||||
* ASSUMES INP_WLOCK is already held
|
||||
*/
|
||||
void
|
||||
sctp_clear_cachedkeys_ep(struct sctp_inpcb *inp, uint16_t keyid)
|
||||
@ -1304,8 +1366,9 @@ sctp_clear_cachedkeys_ep(struct sctp_inpcb *inp, uint16_t keyid)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* delete a shared key from an association ASSUMES TCB_LOCK is already held
|
||||
/*-
|
||||
* delete a shared key from an association
|
||||
* ASSUMES TCB_LOCK is already held
|
||||
*/
|
||||
int
|
||||
sctp_delete_sharedkey(struct sctp_tcb *stcb, uint16_t keyid)
|
||||
@ -1316,7 +1379,7 @@ sctp_delete_sharedkey(struct sctp_tcb *stcb, uint16_t keyid)
|
||||
return (-1);
|
||||
|
||||
/* is the keyid the assoc active sending key */
|
||||
if (keyid == stcb->asoc.authinfo.assoc_keyid)
|
||||
if (keyid == stcb->asoc.authinfo.active_keyid)
|
||||
return (-1);
|
||||
|
||||
/* does the key exist? */
|
||||
@ -1324,6 +1387,10 @@ sctp_delete_sharedkey(struct sctp_tcb *stcb, uint16_t keyid)
|
||||
if (skey == NULL)
|
||||
return (-1);
|
||||
|
||||
/* are there other refcount holders on the key? */
|
||||
if (skey->refcount > 1)
|
||||
return (-1);
|
||||
|
||||
/* remove it */
|
||||
LIST_REMOVE(skey, next);
|
||||
sctp_free_sharedkey(skey); /* frees skey->key as well */
|
||||
@ -1333,35 +1400,29 @@ sctp_delete_sharedkey(struct sctp_tcb *stcb, uint16_t keyid)
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* deletes a shared key from the endpoint ASSUMES INP_WLOCK is already held
|
||||
/*-
|
||||
* deletes a shared key from the endpoint
|
||||
* ASSUMES INP_WLOCK is already held
|
||||
*/
|
||||
int
|
||||
sctp_delete_sharedkey_ep(struct sctp_inpcb *inp, uint16_t keyid)
|
||||
{
|
||||
sctp_sharedkey_t *skey;
|
||||
struct sctp_tcb *stcb;
|
||||
|
||||
if (inp == NULL)
|
||||
return (-1);
|
||||
|
||||
/* is the keyid the active sending key on the endpoint or any assoc */
|
||||
/* is the keyid the active sending key on the endpoint */
|
||||
if (keyid == inp->sctp_ep.default_keyid)
|
||||
return (-1);
|
||||
LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
|
||||
SCTP_TCB_LOCK(stcb);
|
||||
if (keyid == stcb->asoc.authinfo.assoc_keyid) {
|
||||
SCTP_TCB_UNLOCK(stcb);
|
||||
return (-1);
|
||||
}
|
||||
SCTP_TCB_UNLOCK(stcb);
|
||||
}
|
||||
|
||||
/* does the key exist? */
|
||||
skey = sctp_find_sharedkey(&inp->sctp_ep.shared_keys, keyid);
|
||||
if (skey == NULL)
|
||||
return (-1);
|
||||
|
||||
/* endpoint keys are not refcounted */
|
||||
|
||||
/* remove it */
|
||||
LIST_REMOVE(skey, next);
|
||||
sctp_free_sharedkey(skey); /* frees skey->key as well */
|
||||
@ -1371,60 +1432,36 @@ sctp_delete_sharedkey_ep(struct sctp_inpcb *inp, uint16_t keyid)
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* set the active key on an association ASSUME TCB_LOCK is already held
|
||||
/*-
|
||||
* set the active key on an association
|
||||
* ASSUMES TCB_LOCK is already held
|
||||
*/
|
||||
int
|
||||
sctp_auth_setactivekey(struct sctp_tcb *stcb, uint16_t keyid)
|
||||
{
|
||||
sctp_sharedkey_t *skey = NULL;
|
||||
sctp_key_t *key = NULL;
|
||||
int using_ep_key = 0;
|
||||
|
||||
/* find the key on the assoc */
|
||||
skey = sctp_find_sharedkey(&stcb->asoc.shared_keys, keyid);
|
||||
if (skey == NULL) {
|
||||
/* if not on the assoc, find the key on the endpoint */
|
||||
atomic_add_int(&stcb->asoc.refcnt, 1);
|
||||
SCTP_TCB_UNLOCK(stcb);
|
||||
SCTP_INP_RLOCK(stcb->sctp_ep);
|
||||
SCTP_TCB_LOCK(stcb);
|
||||
atomic_add_int(&stcb->asoc.refcnt, -1);
|
||||
skey = sctp_find_sharedkey(&stcb->sctp_ep->sctp_ep.shared_keys,
|
||||
keyid);
|
||||
using_ep_key = 1;
|
||||
}
|
||||
if (skey == NULL) {
|
||||
/* that key doesn't exist */
|
||||
if (using_ep_key) {
|
||||
SCTP_INP_RUNLOCK(stcb->sctp_ep);
|
||||
}
|
||||
return (-1);
|
||||
}
|
||||
/* get the shared key text */
|
||||
key = skey->key;
|
||||
|
||||
/* free any existing cached key */
|
||||
if (stcb->asoc.authinfo.assoc_key != NULL)
|
||||
sctp_free_key(stcb->asoc.authinfo.assoc_key);
|
||||
/* compute a new assoc key and cache it */
|
||||
stcb->asoc.authinfo.assoc_key =
|
||||
sctp_compute_hashkey(stcb->asoc.authinfo.random,
|
||||
stcb->asoc.authinfo.peer_random, key);
|
||||
stcb->asoc.authinfo.assoc_keyid = keyid;
|
||||
#ifdef SCTP_DEBUG
|
||||
if (SCTP_AUTH_DEBUG)
|
||||
sctp_print_key(stcb->asoc.authinfo.assoc_key, "Assoc Key");
|
||||
#endif
|
||||
|
||||
if (using_ep_key) {
|
||||
SCTP_INP_RUNLOCK(stcb->sctp_ep);
|
||||
if ((skey->deactivated) && (skey->refcount > 1)) {
|
||||
/* can't reactivate a deactivated key with other refcounts */
|
||||
return (-1);
|
||||
}
|
||||
/* set the (new) active key */
|
||||
stcb->asoc.authinfo.active_keyid = keyid;
|
||||
/* reset the deactivated flag */
|
||||
skey->deactivated = 0;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* set the active key on an endpoint ASSUMES INP_WLOCK is already held
|
||||
/*-
|
||||
* set the active key on an endpoint
|
||||
* ASSUMES INP_WLOCK is already held
|
||||
*/
|
||||
int
|
||||
sctp_auth_setactivekey_ep(struct sctp_inpcb *inp, uint16_t keyid)
|
||||
@ -1441,6 +1478,69 @@ sctp_auth_setactivekey_ep(struct sctp_inpcb *inp, uint16_t keyid)
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*-
|
||||
* deactivates a shared key from the association
|
||||
* ASSUMES INP_WLOCK is already held
|
||||
*/
|
||||
int
|
||||
sctp_deact_sharedkey(struct sctp_tcb *stcb, uint16_t keyid)
|
||||
{
|
||||
sctp_sharedkey_t *skey;
|
||||
|
||||
if (stcb == NULL)
|
||||
return (-1);
|
||||
|
||||
/* is the keyid the assoc active sending key */
|
||||
if (keyid == stcb->asoc.authinfo.active_keyid)
|
||||
return (-1);
|
||||
|
||||
/* does the key exist? */
|
||||
skey = sctp_find_sharedkey(&stcb->asoc.shared_keys, keyid);
|
||||
if (skey == NULL)
|
||||
return (-1);
|
||||
|
||||
/* are there other refcount holders on the key? */
|
||||
if (skey->refcount == 1) {
|
||||
/* no other users, send a notification for this key */
|
||||
sctp_ulp_notify(SCTP_NOTIFY_AUTH_FREE_KEY, stcb, keyid, 0,
|
||||
SCTP_SO_LOCKED);
|
||||
}
|
||||
/* mark the key as deactivated */
|
||||
skey->deactivated = 1;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*-
|
||||
* deactivates a shared key from the endpoint
|
||||
* ASSUMES INP_WLOCK is already held
|
||||
*/
|
||||
int
|
||||
sctp_deact_sharedkey_ep(struct sctp_inpcb *inp, uint16_t keyid)
|
||||
{
|
||||
sctp_sharedkey_t *skey;
|
||||
|
||||
if (inp == NULL)
|
||||
return (-1);
|
||||
|
||||
/* is the keyid the active sending key on the endpoint */
|
||||
if (keyid == inp->sctp_ep.default_keyid)
|
||||
return (-1);
|
||||
|
||||
/* does the key exist? */
|
||||
skey = sctp_find_sharedkey(&inp->sctp_ep.shared_keys, keyid);
|
||||
if (skey == NULL)
|
||||
return (-1);
|
||||
|
||||
/* endpoint keys are not refcounted */
|
||||
|
||||
/* remove it */
|
||||
LIST_REMOVE(skey, next);
|
||||
sctp_free_sharedkey(skey); /* frees skey->key as well */
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* get local authentication parameters from cookie (from INIT-ACK)
|
||||
*/
|
||||
@ -1581,9 +1681,13 @@ sctp_auth_get_cookie_params(struct sctp_tcb *stcb, struct mbuf *m,
|
||||
/* negotiate what HMAC to use for the peer */
|
||||
stcb->asoc.peer_hmac_id = sctp_negotiate_hmacid(stcb->asoc.peer_hmacs,
|
||||
stcb->asoc.local_hmacs);
|
||||
|
||||
/* copy defaults from the endpoint */
|
||||
/* FIX ME: put in cookie? */
|
||||
stcb->asoc.authinfo.assoc_keyid = stcb->sctp_ep->sctp_ep.default_keyid;
|
||||
stcb->asoc.authinfo.active_keyid = stcb->sctp_ep->sctp_ep.default_keyid;
|
||||
/* copy out the shared key list (by reference) from the endpoint */
|
||||
(void)sctp_copy_skeylist(&stcb->sctp_ep->sctp_ep.shared_keys,
|
||||
&stcb->asoc.shared_keys);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1591,7 +1695,7 @@ sctp_auth_get_cookie_params(struct sctp_tcb *stcb, struct mbuf *m,
|
||||
*/
|
||||
void
|
||||
sctp_fill_hmac_digest_m(struct mbuf *m, uint32_t auth_offset,
|
||||
struct sctp_auth_chunk *auth, struct sctp_tcb *stcb)
|
||||
struct sctp_auth_chunk *auth, struct sctp_tcb *stcb, uint16_t keyid)
|
||||
{
|
||||
uint32_t digestlen;
|
||||
sctp_sharedkey_t *skey;
|
||||
@ -1603,15 +1707,15 @@ sctp_fill_hmac_digest_m(struct mbuf *m, uint32_t auth_offset,
|
||||
/* zero the digest + chunk padding */
|
||||
digestlen = sctp_get_hmac_digest_len(stcb->asoc.peer_hmac_id);
|
||||
bzero(auth->hmac, SCTP_SIZE32(digestlen));
|
||||
/* is an assoc key cached? */
|
||||
if (stcb->asoc.authinfo.assoc_key == NULL) {
|
||||
skey = sctp_find_sharedkey(&stcb->asoc.shared_keys,
|
||||
stcb->asoc.authinfo.assoc_keyid);
|
||||
if (skey == NULL) {
|
||||
/* not in the assoc list, so check the endpoint list */
|
||||
skey = sctp_find_sharedkey(&stcb->sctp_ep->sctp_ep.shared_keys,
|
||||
stcb->asoc.authinfo.assoc_keyid);
|
||||
|
||||
/* is the desired key cached? */
|
||||
if ((keyid != stcb->asoc.authinfo.assoc_keyid) ||
|
||||
(stcb->asoc.authinfo.assoc_key == NULL)) {
|
||||
if (stcb->asoc.authinfo.assoc_key != NULL) {
|
||||
/* free the old cached key */
|
||||
sctp_free_key(stcb->asoc.authinfo.assoc_key);
|
||||
}
|
||||
skey = sctp_find_sharedkey(&stcb->asoc.shared_keys, keyid);
|
||||
/* the only way skey is NULL is if null key id 0 is used */
|
||||
if (skey != NULL)
|
||||
key = skey->key;
|
||||
@ -1621,6 +1725,7 @@ sctp_fill_hmac_digest_m(struct mbuf *m, uint32_t auth_offset,
|
||||
stcb->asoc.authinfo.assoc_key =
|
||||
sctp_compute_hashkey(stcb->asoc.authinfo.random,
|
||||
stcb->asoc.authinfo.peer_random, key);
|
||||
stcb->asoc.authinfo.assoc_keyid = keyid;
|
||||
SCTPDBG(SCTP_DEBUG_AUTH1, "caching key id %u\n",
|
||||
stcb->asoc.authinfo.assoc_keyid);
|
||||
#ifdef SCTP_DEBUG
|
||||
@ -1630,11 +1735,10 @@ sctp_fill_hmac_digest_m(struct mbuf *m, uint32_t auth_offset,
|
||||
#endif
|
||||
}
|
||||
/* set in the active key id */
|
||||
auth->shared_key_id = htons(stcb->asoc.authinfo.assoc_keyid);
|
||||
auth->shared_key_id = htons(keyid);
|
||||
|
||||
/* compute and fill in the digest */
|
||||
(void)sctp_compute_hmac_m(stcb->asoc.peer_hmac_id,
|
||||
stcb->asoc.authinfo.assoc_key,
|
||||
(void)sctp_compute_hmac_m(stcb->asoc.peer_hmac_id, stcb->asoc.authinfo.assoc_key,
|
||||
m, auth_offset, auth->hmac);
|
||||
}
|
||||
|
||||
@ -1671,9 +1775,11 @@ sctp_bzero_m(struct mbuf *m, uint32_t m_offset, uint32_t size)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* process the incoming Authentication chunk return codes: -1 on any
|
||||
* authentication error 0 on authentication verification
|
||||
/*-
|
||||
* process the incoming Authentication chunk
|
||||
* return codes:
|
||||
* -1 on any authentication error
|
||||
* 0 on authentication verification
|
||||
*/
|
||||
int
|
||||
sctp_handle_auth(struct sctp_tcb *stcb, struct sctp_auth_chunk *auth,
|
||||
@ -1736,12 +1842,8 @@ sctp_handle_auth(struct sctp_tcb *stcb, struct sctp_auth_chunk *auth,
|
||||
if ((stcb->asoc.authinfo.recv_key == NULL) ||
|
||||
(stcb->asoc.authinfo.recv_keyid != shared_key_id)) {
|
||||
/* find the shared key on the assoc first */
|
||||
skey = sctp_find_sharedkey(&stcb->asoc.shared_keys, shared_key_id);
|
||||
if (skey == NULL) {
|
||||
/* if not on the assoc, find it on the endpoint */
|
||||
skey = sctp_find_sharedkey(&stcb->sctp_ep->sctp_ep.shared_keys,
|
||||
shared_key_id);
|
||||
}
|
||||
skey = sctp_find_sharedkey(&stcb->asoc.shared_keys,
|
||||
shared_key_id);
|
||||
/* if the shared key isn't found, discard the chunk */
|
||||
if (skey == NULL) {
|
||||
SCTP_STAT_INCR(sctps_recvivalkeyid);
|
||||
@ -1758,7 +1860,8 @@ sctp_handle_auth(struct sctp_tcb *stcb, struct sctp_auth_chunk *auth,
|
||||
* *)stcb->asoc.authinfo.recv_keyid);
|
||||
*/
|
||||
sctp_notify_authentication(stcb, SCTP_AUTH_NEWKEY,
|
||||
shared_key_id, stcb->asoc.authinfo.recv_keyid);
|
||||
shared_key_id, stcb->asoc.authinfo.recv_keyid,
|
||||
SCTP_SO_NOT_LOCKED);
|
||||
/* compute a new recv assoc key and cache it */
|
||||
if (stcb->asoc.authinfo.recv_key != NULL)
|
||||
sctp_free_key(stcb->asoc.authinfo.recv_key);
|
||||
@ -1801,7 +1904,11 @@ sctp_handle_auth(struct sctp_tcb *stcb, struct sctp_auth_chunk *auth,
|
||||
*/
|
||||
void
|
||||
sctp_notify_authentication(struct sctp_tcb *stcb, uint32_t indication,
|
||||
uint16_t keyid, uint16_t alt_keyid)
|
||||
uint16_t keyid, uint16_t alt_keyid, int so_locked
|
||||
#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
|
||||
SCTP_UNUSED
|
||||
#endif
|
||||
)
|
||||
{
|
||||
struct mbuf *m_notify;
|
||||
struct sctp_authkey_event *auth;
|
||||
@ -1851,11 +1958,11 @@ sctp_notify_authentication(struct sctp_tcb *stcb, uint32_t indication,
|
||||
/* not that we need this */
|
||||
control->tail_mbuf = m_notify;
|
||||
sctp_add_to_readq(stcb->sctp_ep, stcb, control,
|
||||
&stcb->sctp_socket->so_rcv, 1, SCTP_SO_NOT_LOCKED);
|
||||
&stcb->sctp_socket->so_rcv, 1, so_locked);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
/*-
|
||||
* validates the AUTHentication related parameters in an INIT/INIT-ACK
|
||||
* Note: currently only used for INIT as INIT-ACK is handled inline
|
||||
* with sctp_load_addresses_from_init()
|
||||
@ -2027,7 +2134,11 @@ sctp_initialize_auth_params(struct sctp_inpcb *inp, struct sctp_tcb *stcb)
|
||||
}
|
||||
}
|
||||
/* copy defaults from the endpoint */
|
||||
stcb->asoc.authinfo.assoc_keyid = inp->sctp_ep.default_keyid;
|
||||
stcb->asoc.authinfo.active_keyid = inp->sctp_ep.default_keyid;
|
||||
|
||||
/* copy out the shared key list (by reference) from the endpoint */
|
||||
(void)sctp_copy_skeylist(&inp->sctp_ep.shared_keys,
|
||||
&stcb->asoc.shared_keys);
|
||||
|
||||
/* now set the concatenated key (random + chunks + hmacs) */
|
||||
#ifdef SCTP_AUTH_DRAFT_04
|
||||
@ -2135,11 +2246,13 @@ sctp_test_hmac_sha1(void)
|
||||
uint32_t digestlen = 20;
|
||||
int failed = 0;
|
||||
|
||||
/*
|
||||
* test_case = 1 key =
|
||||
* 0x0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b key_len = 20
|
||||
* data = "Hi There" data_len = 8 digest =
|
||||
* 0xb617318655057264e28bc0b6fb378c8ef146be00
|
||||
/*-
|
||||
* test_case = 1
|
||||
* key = 0x0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b
|
||||
* key_len = 20
|
||||
* data = "Hi There"
|
||||
* data_len = 8
|
||||
* digest = 0xb617318655057264e28bc0b6fb378c8ef146be00
|
||||
*/
|
||||
keylen = 20;
|
||||
memset(key, 0x0b, keylen);
|
||||
@ -2150,10 +2263,13 @@ sctp_test_hmac_sha1(void)
|
||||
text, textlen, digest, digestlen) < 0)
|
||||
failed++;
|
||||
|
||||
/*
|
||||
* test_case = 2 key = "Jefe" key_len = 4 data =
|
||||
* "what do ya want for nothing?" data_len = 28 digest =
|
||||
* 0xeffcdf6ae5eb2fa2d27416d5f184df9c259a7c79
|
||||
/*-
|
||||
* test_case = 2
|
||||
* key = "Jefe"
|
||||
* key_len = 4
|
||||
* data = "what do ya want for nothing?"
|
||||
* data_len = 28
|
||||
* digest = 0xeffcdf6ae5eb2fa2d27416d5f184df9c259a7c79
|
||||
*/
|
||||
keylen = 4;
|
||||
strcpy(key, "Jefe");
|
||||
@ -2164,11 +2280,13 @@ sctp_test_hmac_sha1(void)
|
||||
text, textlen, digest, digestlen) < 0)
|
||||
failed++;
|
||||
|
||||
/*
|
||||
* test_case = 3 key =
|
||||
* 0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa key_len = 20
|
||||
* data = 0xdd repeated 50 times data_len = 50 digest
|
||||
* = 0x125d7342b9ac11cd91a39af48aa17b4f63f175d3
|
||||
/*-
|
||||
* test_case = 3
|
||||
* key = 0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||
* key_len = 20
|
||||
* data = 0xdd repeated 50 times
|
||||
* data_len = 50
|
||||
* digest = 0x125d7342b9ac11cd91a39af48aa17b4f63f175d3
|
||||
*/
|
||||
keylen = 20;
|
||||
memset(key, 0xaa, keylen);
|
||||
@ -2179,11 +2297,13 @@ sctp_test_hmac_sha1(void)
|
||||
text, textlen, digest, digestlen) < 0)
|
||||
failed++;
|
||||
|
||||
/*
|
||||
* test_case = 4 key =
|
||||
* 0x0102030405060708090a0b0c0d0e0f10111213141516171819 key_len = 25
|
||||
* data = 0xcd repeated 50 times data_len = 50 digest
|
||||
* = 0x4c9007f4026250c6bc8414f9bf50c86c2d7235da
|
||||
/*-
|
||||
* test_case = 4
|
||||
* key = 0x0102030405060708090a0b0c0d0e0f10111213141516171819
|
||||
* key_len = 25
|
||||
* data = 0xcd repeated 50 times
|
||||
* data_len = 50
|
||||
* digest = 0x4c9007f4026250c6bc8414f9bf50c86c2d7235da
|
||||
*/
|
||||
keylen = 25;
|
||||
memcpy(key, "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19", keylen);
|
||||
@ -2194,12 +2314,14 @@ sctp_test_hmac_sha1(void)
|
||||
text, textlen, digest, digestlen) < 0)
|
||||
failed++;
|
||||
|
||||
/*
|
||||
* test_case = 5 key =
|
||||
* 0x0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c key_len = 20
|
||||
* data = "Test With Truncation" data_len = 20 digest
|
||||
* = 0x4c1a03424b55e07fe7f27be1d58bb9324a9a5a04 digest-96 =
|
||||
* 0x4c1a03424b55e07fe7f27be1
|
||||
/*-
|
||||
* test_case = 5
|
||||
* key = 0x0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c
|
||||
* key_len = 20
|
||||
* data = "Test With Truncation"
|
||||
* data_len = 20
|
||||
* digest = 0x4c1a03424b55e07fe7f27be1d58bb9324a9a5a04
|
||||
* digest-96 = 0x4c1a03424b55e07fe7f27be1
|
||||
*/
|
||||
keylen = 20;
|
||||
memset(key, 0x0c, keylen);
|
||||
@ -2210,11 +2332,13 @@ sctp_test_hmac_sha1(void)
|
||||
text, textlen, digest, digestlen) < 0)
|
||||
failed++;
|
||||
|
||||
/*
|
||||
* test_case = 6 key = 0xaa repeated 80 times key_len
|
||||
* = 80 data = "Test Using Larger Than Block-Size Key -
|
||||
* Hash Key First" data_len = 54 digest =
|
||||
* 0xaa4ae5e15272d00e95705637ce8a3b55ed402112
|
||||
/*-
|
||||
* test_case = 6
|
||||
* key = 0xaa repeated 80 times
|
||||
* key_len = 80
|
||||
* data = "Test Using Larger Than Block-Size Key - Hash Key First"
|
||||
* data_len = 54
|
||||
* digest = 0xaa4ae5e15272d00e95705637ce8a3b55ed402112
|
||||
*/
|
||||
keylen = 80;
|
||||
memset(key, 0xaa, keylen);
|
||||
@ -2225,11 +2349,13 @@ sctp_test_hmac_sha1(void)
|
||||
text, textlen, digest, digestlen) < 0)
|
||||
failed++;
|
||||
|
||||
/*
|
||||
* test_case = 7 key = 0xaa repeated 80 times key_len
|
||||
* = 80 data = "Test Using Larger Than Block-Size Key and
|
||||
* Larger Than One Block-Size Data" data_len = 73 digest =
|
||||
* 0xe8e99d0f45237d786d6bbaa7965c7808bbff1a91
|
||||
/*-
|
||||
* test_case = 7
|
||||
* key = 0xaa repeated 80 times
|
||||
* key_len = 80
|
||||
* data = "Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data"
|
||||
* data_len = 73
|
||||
* digest = 0xe8e99d0f45237d786d6bbaa7965c7808bbff1a91
|
||||
*/
|
||||
keylen = 80;
|
||||
memset(key, 0xaa, keylen);
|
||||
@ -2261,10 +2387,13 @@ sctp_test_hmac_md5(void)
|
||||
uint32_t digestlen = 16;
|
||||
int failed = 0;
|
||||
|
||||
/*
|
||||
* test_case = 1 key = 0x0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b
|
||||
* key_len = 16 data = "Hi There" data_len = 8 digest =
|
||||
* 0x9294727a3638bb1c13f48ef8158bfc9d
|
||||
/*-
|
||||
* test_case = 1
|
||||
* key = 0x0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b
|
||||
* key_len = 16
|
||||
* data = "Hi There"
|
||||
* data_len = 8
|
||||
* digest = 0x9294727a3638bb1c13f48ef8158bfc9d
|
||||
*/
|
||||
keylen = 16;
|
||||
memset(key, 0x0b, keylen);
|
||||
@ -2275,10 +2404,13 @@ sctp_test_hmac_md5(void)
|
||||
text, textlen, digest, digestlen) < 0)
|
||||
failed++;
|
||||
|
||||
/*
|
||||
* test_case = 2 key = "Jefe" key_len = 4 data =
|
||||
* "what do ya want for nothing?" data_len = 28 digest =
|
||||
* 0x750c783e6ab0b503eaa86e310a5db738
|
||||
/*-
|
||||
* test_case = 2
|
||||
* key = "Jefe"
|
||||
* key_len = 4
|
||||
* data = "what do ya want for nothing?"
|
||||
* data_len = 28
|
||||
* digest = 0x750c783e6ab0b503eaa86e310a5db738
|
||||
*/
|
||||
keylen = 4;
|
||||
strcpy(key, "Jefe");
|
||||
@ -2289,10 +2421,13 @@ sctp_test_hmac_md5(void)
|
||||
text, textlen, digest, digestlen) < 0)
|
||||
failed++;
|
||||
|
||||
/*
|
||||
* test_case = 3 key = 0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||
* key_len = 16 data = 0xdd repeated 50 times data_len = 50
|
||||
* digest = 0x56be34521d144c88dbb8c733f0e8b3f6
|
||||
/*-
|
||||
* test_case = 3
|
||||
* key = 0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||
* key_len = 16
|
||||
* data = 0xdd repeated 50 times
|
||||
* data_len = 50
|
||||
* digest = 0x56be34521d144c88dbb8c733f0e8b3f6
|
||||
*/
|
||||
keylen = 16;
|
||||
memset(key, 0xaa, keylen);
|
||||
@ -2303,11 +2438,13 @@ sctp_test_hmac_md5(void)
|
||||
text, textlen, digest, digestlen) < 0)
|
||||
failed++;
|
||||
|
||||
/*
|
||||
* test_case = 4 key =
|
||||
* 0x0102030405060708090a0b0c0d0e0f10111213141516171819 key_len = 25
|
||||
* data = 0xcd repeated 50 times data_len = 50 digest
|
||||
* = 0x697eaf0aca3a3aea3a75164746ffaa79
|
||||
/*-
|
||||
* test_case = 4
|
||||
* key = 0x0102030405060708090a0b0c0d0e0f10111213141516171819
|
||||
* key_len = 25
|
||||
* data = 0xcd repeated 50 times
|
||||
* data_len = 50
|
||||
* digest = 0x697eaf0aca3a3aea3a75164746ffaa79
|
||||
*/
|
||||
keylen = 25;
|
||||
memcpy(key, "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19", keylen);
|
||||
@ -2318,11 +2455,14 @@ sctp_test_hmac_md5(void)
|
||||
text, textlen, digest, digestlen) < 0)
|
||||
failed++;
|
||||
|
||||
/*
|
||||
* test_case = 5 key = 0x0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c
|
||||
* key_len = 16 data = "Test With Truncation" data_len = 20
|
||||
* digest = 0x56461ef2342edc00f9bab995690efd4c digest-96
|
||||
* 0x56461ef2342edc00f9bab995
|
||||
/*-
|
||||
* test_case = 5
|
||||
* key = 0x0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c
|
||||
* key_len = 16
|
||||
* data = "Test With Truncation"
|
||||
* data_len = 20
|
||||
* digest = 0x56461ef2342edc00f9bab995690efd4c
|
||||
* digest-96 = 0x56461ef2342edc00f9bab995
|
||||
*/
|
||||
keylen = 16;
|
||||
memset(key, 0x0c, keylen);
|
||||
@ -2333,11 +2473,13 @@ sctp_test_hmac_md5(void)
|
||||
text, textlen, digest, digestlen) < 0)
|
||||
failed++;
|
||||
|
||||
/*
|
||||
* test_case = 6 key = 0xaa repeated 80 times key_len
|
||||
* = 80 data = "Test Using Larger Than Block-Size Key -
|
||||
* Hash Key First" data_len = 54 digest =
|
||||
* 0x6b1ab7fe4bd7bf8f0b62e6ce61b9d0cd
|
||||
/*-
|
||||
* test_case = 6
|
||||
* key = 0xaa repeated 80 times
|
||||
* key_len = 80
|
||||
* data = "Test Using Larger Than Block-Size Key - Hash Key First"
|
||||
* data_len = 54
|
||||
* digest = 0x6b1ab7fe4bd7bf8f0b62e6ce61b9d0cd
|
||||
*/
|
||||
keylen = 80;
|
||||
memset(key, 0xaa, keylen);
|
||||
@ -2348,11 +2490,13 @@ sctp_test_hmac_md5(void)
|
||||
text, textlen, digest, digestlen) < 0)
|
||||
failed++;
|
||||
|
||||
/*
|
||||
* test_case = 7 key = 0xaa repeated 80 times key_len
|
||||
* = 80 data = "Test Using Larger Than Block-Size Key and
|
||||
* Larger Than One Block-Size Data" data_len = 73 digest =
|
||||
* 0x6f630fad67cda0ee1fb1f562db3aa53e
|
||||
/*-
|
||||
* test_case = 7
|
||||
* key = 0xaa repeated 80 times
|
||||
* key_len = 80
|
||||
* data = "Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data"
|
||||
* data_len = 73
|
||||
* digest = 0x6f630fad67cda0ee1fb1f562db3aa53e
|
||||
*/
|
||||
keylen = 80;
|
||||
memset(key, 0xaa, keylen);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*-
|
||||
* Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved.
|
||||
* Copyright (c) 2001-2008, by 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:
|
||||
@ -68,7 +68,9 @@ typedef struct sctp_key {
|
||||
typedef struct sctp_shared_key {
|
||||
LIST_ENTRY(sctp_shared_key) next;
|
||||
sctp_key_t *key; /* key text */
|
||||
uint32_t refcount; /* reference count */
|
||||
uint16_t keyid; /* shared key ID */
|
||||
uint8_t deactivated; /* key is deactivated */
|
||||
} sctp_sharedkey_t;
|
||||
|
||||
LIST_HEAD(sctp_keyhead, sctp_shared_key);
|
||||
@ -91,10 +93,11 @@ typedef struct sctp_authinfo {
|
||||
sctp_key_t *random; /* local random key (concatenated) */
|
||||
uint32_t random_len; /* local random number length for param */
|
||||
sctp_key_t *peer_random;/* peer's random key (concatenated) */
|
||||
sctp_key_t *assoc_key; /* cached concatenated send key */
|
||||
sctp_key_t *recv_key; /* cached concatenated recv key */
|
||||
uint16_t active_keyid; /* active send keyid */
|
||||
uint16_t assoc_keyid; /* current send keyid (cached) */
|
||||
uint16_t recv_keyid; /* last recv keyid (cached) */
|
||||
sctp_key_t *assoc_key; /* cached send key */
|
||||
sctp_key_t *recv_key; /* cached recv key */
|
||||
} sctp_authinfo_t;
|
||||
|
||||
|
||||
@ -117,10 +120,13 @@ 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 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);
|
||||
extern int sctp_pack_auth_chunks(const sctp_auth_chklist_t * list, uint8_t * ptr);
|
||||
extern int
|
||||
extern int
|
||||
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,
|
||||
sctp_auth_chklist_t * list);
|
||||
|
||||
@ -139,14 +145,20 @@ 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);
|
||||
extern void
|
||||
sctp_find_sharedkey(struct sctp_keyhead *shared_keys,
|
||||
uint16_t key_id);
|
||||
extern int
|
||||
sctp_insert_sharedkey(struct sctp_keyhead *shared_keys,
|
||||
sctp_sharedkey_t * new_skey);
|
||||
extern int
|
||||
extern int
|
||||
sctp_copy_skeylist(const struct sctp_keyhead *src,
|
||||
struct sctp_keyhead *dest);
|
||||
|
||||
/* ref counts on shared keys, by key id */
|
||||
extern void sctp_auth_key_acquire(struct sctp_tcb *stcb, uint16_t keyid);
|
||||
extern void sctp_auth_key_release(struct sctp_tcb *stcb, uint16_t keyid);
|
||||
|
||||
|
||||
/* hmac list handling */
|
||||
extern sctp_hmaclist_t *sctp_alloc_hmaclist(uint8_t num_hmacs);
|
||||
extern void sctp_free_hmaclist(sctp_hmaclist_t * list);
|
||||
@ -167,25 +179,24 @@ extern void sctp_free_authinfo(sctp_authinfo_t * authinfo);
|
||||
/* keyed-HMAC functions */
|
||||
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
|
||||
extern uint32_t
|
||||
sctp_hmac(uint16_t hmac_algo, uint8_t * key, uint32_t keylen,
|
||||
uint8_t * text, uint32_t textlen, uint8_t * digest);
|
||||
extern int
|
||||
extern int
|
||||
sctp_verify_hmac(uint16_t hmac_algo, uint8_t * key, uint32_t keylen,
|
||||
uint8_t * text, uint32_t textlen, uint8_t * digest,
|
||||
uint32_t digestlen);
|
||||
extern uint32_t
|
||||
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,
|
||||
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 */
|
||||
extern uint32_t
|
||||
extern uint32_t
|
||||
sctp_hmac_m(uint16_t hmac_algo, uint8_t * key, uint32_t keylen,
|
||||
struct mbuf *m, uint32_t m_offset, uint8_t * digest, uint32_t trailer);
|
||||
extern uint32_t
|
||||
sctp_compute_hmac_m(uint16_t hmac_algo, sctp_key_t * key, struct mbuf *m,
|
||||
uint32_t m_offset, uint8_t * digest);
|
||||
extern uint32_t
|
||||
sctp_compute_hmac_m(uint16_t hmac_algo, sctp_key_t * key,
|
||||
struct mbuf *m, uint32_t m_offset, uint8_t * digest);
|
||||
|
||||
/*
|
||||
* authentication routines
|
||||
@ -196,31 +207,31 @@ extern int sctp_delete_sharedkey(struct sctp_tcb *stcb, uint16_t keyid);
|
||||
extern int sctp_delete_sharedkey_ep(struct sctp_inpcb *inp, uint16_t keyid);
|
||||
extern int sctp_auth_setactivekey(struct sctp_tcb *stcb, uint16_t keyid);
|
||||
extern int sctp_auth_setactivekey_ep(struct sctp_inpcb *inp, uint16_t keyid);
|
||||
extern int sctp_deact_sharedkey(struct sctp_tcb *stcb, uint16_t keyid);
|
||||
extern int sctp_deact_sharedkey_ep(struct sctp_inpcb *inp, uint16_t keyid);
|
||||
|
||||
extern void
|
||||
extern void
|
||||
sctp_auth_get_cookie_params(struct sctp_tcb *stcb, struct mbuf *m,
|
||||
uint32_t offset, uint32_t length);
|
||||
extern void
|
||||
extern void
|
||||
sctp_fill_hmac_digest_m(struct mbuf *m, uint32_t auth_offset,
|
||||
struct sctp_auth_chunk *auth,
|
||||
struct sctp_tcb *stcb);
|
||||
struct sctp_auth_chunk *auth, struct sctp_tcb *stcb, uint16_t key_id);
|
||||
extern struct mbuf *
|
||||
sctp_add_auth_chunk(struct mbuf *m, struct mbuf **m_end,
|
||||
struct sctp_auth_chunk **auth_ret,
|
||||
uint32_t * offset, struct sctp_tcb *stcb,
|
||||
uint8_t chunk);
|
||||
extern int
|
||||
struct sctp_auth_chunk **auth_ret, uint32_t * offset,
|
||||
struct sctp_tcb *stcb, uint8_t chunk);
|
||||
extern int
|
||||
sctp_handle_auth(struct sctp_tcb *stcb, struct sctp_auth_chunk *ch,
|
||||
struct mbuf *m, uint32_t offset);
|
||||
extern void
|
||||
extern void
|
||||
sctp_notify_authentication(struct sctp_tcb *stcb,
|
||||
uint32_t indication, uint16_t keyid,
|
||||
uint16_t alt_keyid);
|
||||
extern int
|
||||
sctp_validate_init_auth_params(struct mbuf *m, int offset, int limit);
|
||||
extern void
|
||||
sctp_initialize_auth_params(struct sctp_inpcb *inp, struct sctp_tcb *stcb);
|
||||
|
||||
uint32_t indication, uint16_t keyid, uint16_t alt_keyid, int so_locked);
|
||||
extern int
|
||||
sctp_validate_init_auth_params(struct mbuf *m, int offset,
|
||||
int limit);
|
||||
extern void
|
||||
sctp_initialize_auth_params(struct sctp_inpcb *inp,
|
||||
struct sctp_tcb *stcb);
|
||||
|
||||
/* test functions */
|
||||
extern void sctp_test_hmac_sha1(void);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*-
|
||||
* Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved.
|
||||
* Copyright (c) 2001-2008, by 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:
|
||||
@ -313,7 +313,6 @@ __FBSDID("$FreeBSD$");
|
||||
/* Minimum number of bytes read by user before we
|
||||
* condsider doing a rwnd update
|
||||
*/
|
||||
#define SCTP_MIN_READ_BEFORE_CONSIDERING 3000
|
||||
|
||||
/*
|
||||
* default HMAC for cookies, etc... use one of the AUTH HMAC id's
|
||||
@ -382,6 +381,14 @@ __FBSDID("$FreeBSD$");
|
||||
* hit this value) */
|
||||
#define SCTP_DATAGRAM_RESEND 4
|
||||
#define SCTP_DATAGRAM_ACKED 10010
|
||||
/* EY
|
||||
* If a tsn is nr-gapped, its first tagged as NR_MARKED and then NR_ACKED
|
||||
* When yet another nr-sack is received, if a particular TSN's sent tag
|
||||
* is observed to be NR_ACKED after gap-ack info is processed, this implies
|
||||
* that particular TSN is reneged
|
||||
*/
|
||||
#define SCTP_DATAGRAM_NR_ACKED 10020
|
||||
#define SCTP_DATAGRAM_NR_MARKED 20005
|
||||
#define SCTP_DATAGRAM_MARKED 20010
|
||||
#define SCTP_FORWARD_TSN_SKIP 30010
|
||||
|
||||
@ -465,6 +472,9 @@ __FBSDID("$FreeBSD$");
|
||||
#define SCTP_SET_PRIM_ADDR 0xc004
|
||||
#define SCTP_SUCCESS_REPORT 0xc005
|
||||
#define SCTP_ULP_ADAPTATION 0xc006
|
||||
/* behave-nat-draft */
|
||||
#define SCTP_HAS_NAT_SUPPORT 0xc007
|
||||
#define SCTP_NAT_VTAGS 0xc008
|
||||
|
||||
/* Notification error codes */
|
||||
#define SCTP_NOTIFY_DATAGRAM_UNSENT 0x0001
|
||||
@ -553,7 +563,13 @@ __FBSDID("$FreeBSD$");
|
||||
#define SCTP_INITIAL_MAPPING_ARRAY 16
|
||||
/* how much we grow the mapping array each call */
|
||||
#define SCTP_MAPPING_ARRAY_INCR 32
|
||||
|
||||
/* EY 05/13/08 - nr_sack version of the previous 3 constants */
|
||||
/* Maximum the nr mapping array will grow to (TSN mapping array) */
|
||||
#define SCTP_NR_MAPPING_ARRAY 512
|
||||
/* size of the inital malloc on the nr mapping array */
|
||||
#define SCTP_INITIAL_NR_MAPPING_ARRAY 16
|
||||
/* how much we grow the nr mapping array each call */
|
||||
#define SCTP_NR_MAPPING_ARRAY_INCR 32
|
||||
/*
|
||||
* Here we define the timer types used by the implementation as arguments in
|
||||
* the set/get timer type calls.
|
||||
@ -607,7 +623,6 @@ __FBSDID("$FreeBSD$");
|
||||
* Number of ticks before the soxwakeup() event that is delayed is sent AFTER
|
||||
* the accept() call
|
||||
*/
|
||||
#define SCTP_EVENTWAKEUP_WAIT_TICKS 3000
|
||||
|
||||
/*
|
||||
* Of course we really don't collect stale cookies, being folks of decerning
|
||||
@ -616,7 +631,6 @@ __FBSDID("$FreeBSD$");
|
||||
* up...this is a implemenation dependent treatment. In ours we do not ask
|
||||
* for a extension of time, but just retry this many times...
|
||||
*/
|
||||
#define SCTP_MAX_STALE_COOKIES_I_COLLECT 10
|
||||
|
||||
/* max number of TSN's dup'd that I will hold */
|
||||
#define SCTP_MAX_DUP_TSNS 20
|
||||
@ -625,11 +639,8 @@ __FBSDID("$FreeBSD$");
|
||||
* Here we define the types used when setting the retry amounts.
|
||||
*/
|
||||
/* constants for type of set */
|
||||
#define SCTP_MAXATTEMPT_INIT 2
|
||||
#define SCTP_MAXATTEMPT_SEND 3
|
||||
|
||||
/* Maximum TSN's we will summarize in a drop report */
|
||||
#define SCTP_MAX_DROP_REPORT 16
|
||||
|
||||
/* How many drop re-attempts we make on INIT/COOKIE-ECHO */
|
||||
#define SCTP_RETRY_DROPPED_THRESH 4
|
||||
@ -638,7 +649,6 @@ __FBSDID("$FreeBSD$");
|
||||
* And the max we will keep a history of in the tcb which MUST be lower than
|
||||
* 256.
|
||||
*/
|
||||
#define SCTP_MAX_DROP_SAVE_REPORT 16
|
||||
|
||||
/*
|
||||
* Here we define the default timers and the default number of attemts we
|
||||
@ -711,15 +721,8 @@ __FBSDID("$FreeBSD$");
|
||||
#define SCTP_DEF_MAX_PATH_RTX 5
|
||||
|
||||
#define SCTP_DEF_PMTU_RAISE_SEC 600 /* 10 min between raise attempts */
|
||||
#define SCTP_DEF_PMTU_MIN 600
|
||||
|
||||
|
||||
#define SCTP_MSEC_IN_A_SEC 1000
|
||||
#define SCTP_USEC_IN_A_SEC 1000000
|
||||
#define SCTP_NSEC_IN_A_SEC 1000000000
|
||||
|
||||
#define SCTP_MAX_OUTSTANDING_DG 10000
|
||||
|
||||
/* How many streams I request initally by default */
|
||||
#define SCTP_OSTREAM_INITIAL 10
|
||||
|
||||
@ -727,9 +730,7 @@ __FBSDID("$FreeBSD$");
|
||||
* How many smallest_mtu's need to increase before a window update sack is
|
||||
* sent (should be a power of 2).
|
||||
*/
|
||||
#define SCTP_SEG_TO_RWND_UPD 32
|
||||
/* Send window update (incr * this > hiwat). Should be a power of 2 */
|
||||
#define SCTP_SCALE_OF_RWND_TO_UPD 4
|
||||
#define SCTP_MINIMAL_RWND (4096) /* minimal rwnd */
|
||||
|
||||
#define SCTP_ADDRMAX 24
|
||||
@ -786,15 +787,6 @@ __FBSDID("$FreeBSD$");
|
||||
/* amount peer is obligated to have in rwnd or I will abort */
|
||||
#define SCTP_MIN_RWND 1500
|
||||
|
||||
#define SCTP_WINDOW_MIN 1500 /* smallest rwnd can be */
|
||||
#define SCTP_WINDOW_MAX 1048576 /* biggest I can grow rwnd to My playing
|
||||
* around suggests a value greater than 64k
|
||||
* does not do much, I guess via the kernel
|
||||
* limitations on the stream/socket. */
|
||||
|
||||
/* I can handle a 1meg re-assembly */
|
||||
#define SCTP_DEFAULT_MAXMSGREASM 1048576
|
||||
|
||||
#define SCTP_DEFAULT_MAXSEGMENT 65535
|
||||
|
||||
#define SCTP_CHUNK_BUFFER_SIZE 512
|
||||
@ -813,33 +805,35 @@ __FBSDID("$FreeBSD$");
|
||||
/*
|
||||
* SCTP upper layer notifications
|
||||
*/
|
||||
#define SCTP_NOTIFY_ASSOC_UP 1
|
||||
#define SCTP_NOTIFY_ASSOC_DOWN 2
|
||||
#define SCTP_NOTIFY_INTERFACE_DOWN 3
|
||||
#define SCTP_NOTIFY_INTERFACE_UP 4
|
||||
#define SCTP_NOTIFY_DG_FAIL 5
|
||||
#define SCTP_NOTIFY_STRDATA_ERR 6
|
||||
#define SCTP_NOTIFY_ASSOC_ABORTED 7
|
||||
#define SCTP_NOTIFY_PEER_OPENED_STREAM 8
|
||||
#define SCTP_NOTIFY_STREAM_OPENED_OK 9
|
||||
#define SCTP_NOTIFY_ASSOC_RESTART 10
|
||||
#define SCTP_NOTIFY_HB_RESP 11
|
||||
#define SCTP_NOTIFY_ASCONF_SUCCESS 12
|
||||
#define SCTP_NOTIFY_ASCONF_FAILED 13
|
||||
#define SCTP_NOTIFY_PEER_SHUTDOWN 14
|
||||
#define SCTP_NOTIFY_ASCONF_ADD_IP 15
|
||||
#define SCTP_NOTIFY_ASCONF_DELETE_IP 16
|
||||
#define SCTP_NOTIFY_ASCONF_SET_PRIMARY 17
|
||||
#define SCTP_NOTIFY_ASSOC_UP 1
|
||||
#define SCTP_NOTIFY_ASSOC_DOWN 2
|
||||
#define SCTP_NOTIFY_INTERFACE_DOWN 3
|
||||
#define SCTP_NOTIFY_INTERFACE_UP 4
|
||||
#define SCTP_NOTIFY_DG_FAIL 5
|
||||
#define SCTP_NOTIFY_STRDATA_ERR 6
|
||||
#define SCTP_NOTIFY_ASSOC_ABORTED 7
|
||||
#define SCTP_NOTIFY_PEER_OPENED_STREAM 8
|
||||
#define SCTP_NOTIFY_STREAM_OPENED_OK 9
|
||||
#define SCTP_NOTIFY_ASSOC_RESTART 10
|
||||
#define SCTP_NOTIFY_HB_RESP 11
|
||||
#define SCTP_NOTIFY_ASCONF_SUCCESS 12
|
||||
#define SCTP_NOTIFY_ASCONF_FAILED 13
|
||||
#define SCTP_NOTIFY_PEER_SHUTDOWN 14
|
||||
#define SCTP_NOTIFY_ASCONF_ADD_IP 15
|
||||
#define SCTP_NOTIFY_ASCONF_DELETE_IP 16
|
||||
#define SCTP_NOTIFY_ASCONF_SET_PRIMARY 17
|
||||
#define SCTP_NOTIFY_PARTIAL_DELVIERY_INDICATION 18
|
||||
#define SCTP_NOTIFY_INTERFACE_CONFIRMED 20
|
||||
#define SCTP_NOTIFY_STR_RESET_RECV 21
|
||||
#define SCTP_NOTIFY_STR_RESET_SEND 22
|
||||
#define SCTP_NOTIFY_STR_RESET_FAILED_OUT 23
|
||||
#define SCTP_NOTIFY_STR_RESET_FAILED_IN 24
|
||||
#define SCTP_NOTIFY_AUTH_NEW_KEY 25
|
||||
#define SCTP_NOTIFY_AUTH_KEY_CONFLICT 26
|
||||
#define SCTP_NOTIFY_SPECIAL_SP_FAIL 27
|
||||
#define SCTP_NOTIFY_MAX 27
|
||||
#define SCTP_NOTIFY_INTERFACE_CONFIRMED 20
|
||||
#define SCTP_NOTIFY_STR_RESET_RECV 21
|
||||
#define SCTP_NOTIFY_STR_RESET_SEND 22
|
||||
#define SCTP_NOTIFY_STR_RESET_FAILED_OUT 23
|
||||
#define SCTP_NOTIFY_STR_RESET_FAILED_IN 24
|
||||
#define SCTP_NOTIFY_AUTH_NEW_KEY 25
|
||||
#define SCTP_NOTIFY_AUTH_FREE_KEY 26
|
||||
#define SCTP_NOTIFY_SPECIAL_SP_FAIL 27
|
||||
#define SCTP_NOTIFY_NO_PEER_AUTH 28
|
||||
#define SCTP_NOTIFY_SENDER_DRY 29
|
||||
#define SCTP_NOTIFY_MAX 29
|
||||
|
||||
/* This is the value for messages that are NOT completely
|
||||
* copied down where we will start to split the message.
|
||||
@ -970,7 +964,6 @@ __FBSDID("$FreeBSD$");
|
||||
#endif /* !IPPROTO_SCTP */
|
||||
|
||||
#define SCTP_MAX_DATA_BUNDLING 256
|
||||
#define SCTP_MAX_CONTROL_BUNDLING 20
|
||||
|
||||
/* modular comparison */
|
||||
/* True if a > b (mod = M) */
|
||||
|
@ -121,6 +121,14 @@ struct sctp_asconf_addr_param { /* an ASCONF address parameter */
|
||||
struct sctp_ipv6addr_param addrp; /* max storage size */
|
||||
} SCTP_PACKED;
|
||||
|
||||
|
||||
struct sctp_asconf_tag_param { /* an ASCONF NAT-Vtag parameter */
|
||||
struct sctp_asconf_paramhdr aph; /* asconf "parameter" */
|
||||
uint32_t local_vtag;
|
||||
uint32_t remote_vtag;
|
||||
} SCTP_PACKED;
|
||||
|
||||
|
||||
struct sctp_asconf_addrv4_param { /* an ASCONF address (v4) parameter */
|
||||
struct sctp_asconf_paramhdr aph; /* asconf "parameter" */
|
||||
struct sctp_ipv4addr_param addrp; /* max storage size */
|
||||
@ -206,6 +214,15 @@ struct sctp_state_cookie { /* this is our definition... */
|
||||
*/
|
||||
} SCTP_PACKED;
|
||||
|
||||
|
||||
/* Used for NAT state error cause */
|
||||
struct sctp_missing_nat_state {
|
||||
uint16_t cause;
|
||||
uint16_t length;
|
||||
uint8_t data[0];
|
||||
} SCTP_PACKED;
|
||||
|
||||
|
||||
struct sctp_inv_mandatory_param {
|
||||
uint16_t cause;
|
||||
uint16_t length;
|
||||
@ -268,6 +285,30 @@ struct sctp_sack_chunk {
|
||||
} SCTP_PACKED;
|
||||
|
||||
|
||||
/* EY Following 3 structs define NR Selective Ack (NR_SACK) chunk */
|
||||
struct sctp_nr_gap_ack_block {
|
||||
uint16_t start; /* NR Gap Ack block start */
|
||||
uint16_t end; /* NR Gap Ack block end */
|
||||
} SCTP_PACKED;
|
||||
|
||||
struct sctp_nr_sack {
|
||||
uint32_t cum_tsn_ack; /* cumulative TSN Ack */
|
||||
uint32_t a_rwnd; /* updated a_rwnd of sender */
|
||||
uint16_t num_gap_ack_blks; /* number of Gap Ack blocks */
|
||||
uint16_t num_nr_gap_ack_blks; /* number of NR Gap Ack blocks */
|
||||
uint16_t num_dup_tsns; /* number of duplicate TSNs */
|
||||
uint16_t reserved; /* not currently used */
|
||||
/* struct sctp_gap_ack_block's follow */
|
||||
/* struct sctp_nr_gap_ack_block's follow */
|
||||
/* uint32_t duplicate_tsn's follow */
|
||||
} SCTP_PACKED;
|
||||
|
||||
struct sctp_nr_sack_chunk {
|
||||
struct sctp_chunkhdr ch;
|
||||
struct sctp_nr_sack nr_sack;
|
||||
} SCTP_PACKED;
|
||||
|
||||
|
||||
/* Heartbeat Request (HEARTBEAT) */
|
||||
struct sctp_heartbeat {
|
||||
struct sctp_heartbeat_info_param hb_info;
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -99,6 +99,16 @@ void
|
||||
sctp_handle_sack(struct mbuf *m, int offset, struct sctp_sack_chunk *, struct sctp_tcb *,
|
||||
struct sctp_nets *, int *, int, uint32_t);
|
||||
|
||||
/* EY does "exactly" the same as sctp_express_handle_sack */
|
||||
void
|
||||
sctp_express_handle_nr_sack(struct sctp_tcb *stcb, uint32_t cumack,
|
||||
uint32_t rwnd, int nonce_sum_flag, int *abort_now);
|
||||
|
||||
/* EY nr_sack version of sctp_handle_sack */
|
||||
void
|
||||
sctp_handle_nr_sack(struct mbuf *m, int offset, struct sctp_nr_sack_chunk *, struct sctp_tcb *,
|
||||
struct sctp_nets *, int *, int, uint32_t);
|
||||
|
||||
/* draft-ietf-tsvwg-usctp */
|
||||
void
|
||||
sctp_handle_forward_tsn(struct sctp_tcb *,
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*-
|
||||
* Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved.
|
||||
* Copyright (c) 2001-2008, by 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:
|
||||
@ -316,6 +316,8 @@ sctp_process_init(struct sctp_init_chunk *cp, struct sctp_tcb *stcb,
|
||||
asoc->streamoutcnt = asoc->pre_open_streams;
|
||||
/* init tsn's */
|
||||
asoc->highest_tsn_inside_map = asoc->asconf_seq_in = ntohl(init->initial_tsn) - 1;
|
||||
/* EY - nr_sack: initialize highest tsn in nr_mapping_array */
|
||||
asoc->highest_tsn_inside_nr_map = asoc->highest_tsn_inside_map;
|
||||
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MAP_LOGGING_ENABLE) {
|
||||
sctp_log_map(0, 5, asoc->highest_tsn_inside_map, SCTP_MAP_SLIDE_RESULT);
|
||||
}
|
||||
@ -323,6 +325,11 @@ sctp_process_init(struct sctp_init_chunk *cp, struct sctp_tcb *stcb,
|
||||
asoc->str_reset_seq_in = asoc->asconf_seq_in + 1;
|
||||
|
||||
asoc->mapping_array_base_tsn = ntohl(init->initial_tsn);
|
||||
/*
|
||||
* EY 05/13/08 - nr_sack: initialize nr_mapping array's base tsn
|
||||
* like above
|
||||
*/
|
||||
asoc->nr_mapping_array_base_tsn = ntohl(init->initial_tsn);
|
||||
asoc->tsn_last_delivered = asoc->cumulative_tsn = asoc->asconf_seq_in;
|
||||
asoc->last_echo_tsn = asoc->asconf_seq_in;
|
||||
asoc->advanced_peer_ack_point = asoc->last_acked_seq;
|
||||
@ -393,6 +400,7 @@ sctp_process_init_ack(struct mbuf *m, int iphlen, int offset,
|
||||
struct mbuf *op_err;
|
||||
int retval, abort_flag;
|
||||
uint32_t initack_limit;
|
||||
int nat_friendly = 0;
|
||||
|
||||
/* First verify that we have no illegal param's */
|
||||
abort_flag = 0;
|
||||
@ -400,7 +408,7 @@ sctp_process_init_ack(struct mbuf *m, int iphlen, int offset,
|
||||
|
||||
op_err = sctp_arethere_unrecognized_parameters(m,
|
||||
(offset + sizeof(struct sctp_init_chunk)),
|
||||
&abort_flag, (struct sctp_chunkhdr *)cp);
|
||||
&abort_flag, (struct sctp_chunkhdr *)cp, &nat_friendly);
|
||||
if (abort_flag) {
|
||||
/* Send an abort and notify peer */
|
||||
sctp_abort_an_association(stcb->sctp_ep, stcb, SCTP_CAUSE_PROTOCOL_VIOLATION, op_err, SCTP_SO_NOT_LOCKED);
|
||||
@ -408,6 +416,7 @@ sctp_process_init_ack(struct mbuf *m, int iphlen, int offset,
|
||||
return (-1);
|
||||
}
|
||||
asoc = &stcb->asoc;
|
||||
asoc->peer_supports_nat = (uint8_t) nat_friendly;
|
||||
/* process the peer's parameters in the INIT-ACK */
|
||||
retval = sctp_process_init((struct sctp_init_chunk *)cp, stcb, net);
|
||||
if (retval < 0) {
|
||||
@ -637,6 +646,69 @@ sctp_handle_heartbeat_ack(struct sctp_heartbeat_chunk *cp,
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
sctp_handle_nat_colliding_state(struct sctp_tcb *stcb)
|
||||
{
|
||||
/*
|
||||
* return 0 means we want you to proceed with the abort non-zero
|
||||
* means no abort processing
|
||||
*/
|
||||
struct sctpasochead *head;
|
||||
|
||||
if (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_COOKIE_WAIT) {
|
||||
/* generate a new vtag and send init */
|
||||
LIST_REMOVE(stcb, sctp_asocs);
|
||||
stcb->asoc.my_vtag = sctp_select_a_tag(stcb->sctp_ep, stcb->sctp_ep->sctp_lport, stcb->rport, 1);
|
||||
head = &SCTP_BASE_INFO(sctp_asochash)[SCTP_PCBHASH_ASOC(stcb->asoc.my_vtag, SCTP_BASE_INFO(hashasocmark))];
|
||||
/*
|
||||
* put it in the bucket in the vtag hash of assoc's for the
|
||||
* system
|
||||
*/
|
||||
LIST_INSERT_HEAD(head, stcb, sctp_asocs);
|
||||
sctp_send_initiate(stcb->sctp_ep, stcb, SCTP_SO_NOT_LOCKED);
|
||||
return (1);
|
||||
}
|
||||
if (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_COOKIE_ECHOED) {
|
||||
/*
|
||||
* treat like a case where the cookie expired i.e.: - dump
|
||||
* current cookie. - generate a new vtag. - resend init.
|
||||
*/
|
||||
/* generate a new vtag and send init */
|
||||
LIST_REMOVE(stcb, sctp_asocs);
|
||||
stcb->asoc.state &= ~SCTP_STATE_COOKIE_ECHOED;
|
||||
stcb->asoc.state |= SCTP_STATE_COOKIE_WAIT;
|
||||
sctp_stop_all_cookie_timers(stcb);
|
||||
sctp_toss_old_cookies(stcb, &stcb->asoc);
|
||||
stcb->asoc.my_vtag = sctp_select_a_tag(stcb->sctp_ep, stcb->sctp_ep->sctp_lport, stcb->rport, 1);
|
||||
head = &SCTP_BASE_INFO(sctp_asochash)[SCTP_PCBHASH_ASOC(stcb->asoc.my_vtag, SCTP_BASE_INFO(hashasocmark))];
|
||||
/*
|
||||
* put it in the bucket in the vtag hash of assoc's for the
|
||||
* system
|
||||
*/
|
||||
LIST_INSERT_HEAD(head, stcb, sctp_asocs);
|
||||
sctp_send_initiate(stcb->sctp_ep, stcb, SCTP_SO_NOT_LOCKED);
|
||||
return (1);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
sctp_handle_nat_missing_state(struct sctp_tcb *stcb,
|
||||
struct sctp_nets *net)
|
||||
{
|
||||
/*
|
||||
* return 0 means we want you to proceed with the abort non-zero
|
||||
* means no abort processing
|
||||
*/
|
||||
if (stcb->asoc.peer_supports_auth == 0) {
|
||||
SCTPDBG(SCTP_DEBUG_INPUT2, "sctp_handle_nat_missing_state: Peer does not support AUTH, cannot send an asconf\n");
|
||||
return (0);
|
||||
}
|
||||
sctp_asconf_send_nat_state_update(stcb, net);
|
||||
return (1);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
sctp_handle_abort(struct sctp_abort_chunk *cp,
|
||||
struct sctp_tcb *stcb, struct sctp_nets *net)
|
||||
@ -645,11 +717,40 @@ sctp_handle_abort(struct sctp_abort_chunk *cp,
|
||||
struct socket *so;
|
||||
|
||||
#endif
|
||||
uint16_t len;
|
||||
|
||||
SCTPDBG(SCTP_DEBUG_INPUT2, "sctp_handle_abort: handling ABORT\n");
|
||||
if (stcb == NULL)
|
||||
return;
|
||||
|
||||
len = ntohs(cp->ch.chunk_length);
|
||||
if (len > sizeof(struct sctp_chunkhdr)) {
|
||||
/*
|
||||
* Need to check the cause codes for our two magic nat
|
||||
* aborts which don't kill the assoc necessarily.
|
||||
*/
|
||||
struct sctp_abort_chunk *cpnext;
|
||||
struct sctp_missing_nat_state *natc;
|
||||
uint16_t cause;
|
||||
|
||||
cpnext = cp;
|
||||
cpnext++;
|
||||
natc = (struct sctp_missing_nat_state *)cpnext;
|
||||
cause = ntohs(natc->cause);
|
||||
if (cause == SCTP_CAUSE_NAT_COLLIDING_STATE) {
|
||||
SCTPDBG(SCTP_DEBUG_INPUT2, "Received Colliding state abort flags:%x\n",
|
||||
cp->ch.chunk_flags);
|
||||
if (sctp_handle_nat_colliding_state(stcb)) {
|
||||
return;
|
||||
}
|
||||
} else if (cause == SCTP_CAUSE_NAT_MISSING_STATE) {
|
||||
SCTPDBG(SCTP_DEBUG_INPUT2, "Received missing state abort flags:%x\n",
|
||||
cp->ch.chunk_flags);
|
||||
if (sctp_handle_nat_missing_state(stcb, net)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* stop any receive timers */
|
||||
sctp_timer_stop(SCTP_TIMER_TYPE_RECV, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_INPUT + SCTP_LOC_6);
|
||||
/* notify user of the abort and clean up... */
|
||||
@ -926,6 +1027,9 @@ sctp_process_unrecog_param(struct sctp_tcb *stcb, struct sctp_paramhdr *phdr)
|
||||
case SCTP_SUPPORTED_CHUNK_EXT:
|
||||
break;
|
||||
/* draft-ietf-tsvwg-addip-sctp */
|
||||
case SCTP_HAS_NAT_SUPPORT:
|
||||
stcb->asoc.peer_supports_nat = 0;
|
||||
break;
|
||||
case SCTP_ECN_NONCE_SUPPORTED:
|
||||
stcb->asoc.peer_supports_ecn_nonce = 0;
|
||||
stcb->asoc.ecn_nonce_allowed = 0;
|
||||
@ -990,6 +1094,20 @@ sctp_handle_error(struct sctp_chunkhdr *ch,
|
||||
SCTPDBG(SCTP_DEBUG_INPUT1, "Software error we got a %d back? We have a bug :/ (or do they?)\n",
|
||||
error_type);
|
||||
break;
|
||||
case SCTP_CAUSE_NAT_COLLIDING_STATE:
|
||||
SCTPDBG(SCTP_DEBUG_INPUT2, "Received Colliding state abort flags:%x\n",
|
||||
ch->chunk_flags);
|
||||
if (sctp_handle_nat_colliding_state(stcb)) {
|
||||
return (0);
|
||||
}
|
||||
break;
|
||||
case SCTP_CAUSE_NAT_MISSING_STATE:
|
||||
SCTPDBG(SCTP_DEBUG_INPUT2, "Received missing state abort flags:%x\n",
|
||||
ch->chunk_flags);
|
||||
if (sctp_handle_nat_missing_state(stcb, net)) {
|
||||
return (0);
|
||||
}
|
||||
break;
|
||||
case SCTP_CAUSE_STALE_COOKIE:
|
||||
/*
|
||||
* We only act if we have echoed a cookie and are
|
||||
@ -1022,9 +1140,9 @@ sctp_handle_error(struct sctp_chunkhdr *ch,
|
||||
return (-1);
|
||||
}
|
||||
/* blast back to INIT state */
|
||||
sctp_toss_old_cookies(stcb, &stcb->asoc);
|
||||
asoc->state &= ~SCTP_STATE_COOKIE_ECHOED;
|
||||
asoc->state |= SCTP_STATE_COOKIE_WAIT;
|
||||
|
||||
sctp_stop_all_cookie_timers(stcb);
|
||||
sctp_send_initiate(stcb->sctp_ep, stcb, SCTP_SO_NOT_LOCKED);
|
||||
}
|
||||
@ -1213,6 +1331,14 @@ sctp_handle_init_ack(struct mbuf *m, int iphlen, int offset,
|
||||
return (0);
|
||||
}
|
||||
|
||||
static struct sctp_tcb *
|
||||
sctp_process_cookie_new(struct mbuf *m, int iphlen, int offset,
|
||||
struct sctphdr *sh, struct sctp_state_cookie *cookie, int cookie_len,
|
||||
struct sctp_inpcb *inp, struct sctp_nets **netp,
|
||||
struct sockaddr *init_src, int *notification,
|
||||
int auth_skipped, uint32_t auth_offset, uint32_t auth_len,
|
||||
uint32_t vrf_id, uint16_t port);
|
||||
|
||||
|
||||
/*
|
||||
* handle a state cookie for an existing association m: input packet mbuf
|
||||
@ -1223,19 +1349,23 @@ sctp_handle_init_ack(struct mbuf *m, int iphlen, int offset,
|
||||
static struct sctp_tcb *
|
||||
sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset,
|
||||
struct sctphdr *sh, struct sctp_state_cookie *cookie, int cookie_len,
|
||||
struct sctp_inpcb *inp, struct sctp_tcb *stcb, struct sctp_nets *net,
|
||||
struct sctp_inpcb *inp, struct sctp_tcb *stcb, struct sctp_nets **netp,
|
||||
struct sockaddr *init_src, int *notification, sctp_assoc_t * sac_assoc_id,
|
||||
uint32_t vrf_id)
|
||||
uint32_t vrf_id, int auth_skipped, uint32_t auth_offset, uint32_t auth_len, uint16_t port)
|
||||
{
|
||||
struct sctp_association *asoc;
|
||||
struct sctp_init_chunk *init_cp, init_buf;
|
||||
struct sctp_init_ack_chunk *initack_cp, initack_buf;
|
||||
struct sctp_nets *net;
|
||||
struct mbuf *op_err;
|
||||
struct sctp_paramhdr *ph;
|
||||
int chk_length;
|
||||
int init_offset, initack_offset, i;
|
||||
int retval;
|
||||
int spec_flag = 0;
|
||||
uint32_t how_indx;
|
||||
|
||||
net = *netp;
|
||||
/* I know that the TCB is non-NULL from the caller */
|
||||
asoc = &stcb->asoc;
|
||||
for (how_indx = 0; how_indx < sizeof(asoc->cookie_how); how_indx++) {
|
||||
@ -1247,9 +1377,6 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset,
|
||||
}
|
||||
if (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_ACK_SENT) {
|
||||
/* SHUTDOWN came in after sending INIT-ACK */
|
||||
struct mbuf *op_err;
|
||||
struct sctp_paramhdr *ph;
|
||||
|
||||
sctp_send_shutdown_ack(stcb, stcb->asoc.primary_destination);
|
||||
op_err = sctp_get_mbuf_for_msg(sizeof(struct sctp_paramhdr),
|
||||
0, M_DONTWAIT, 1, MT_DATA);
|
||||
@ -1457,9 +1584,50 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset,
|
||||
asoc->cookie_how[how_indx] = 6;
|
||||
return (NULL);
|
||||
}
|
||||
if (ntohl(initack_cp->init.initiate_tag) == asoc->my_vtag &&
|
||||
(ntohl(init_cp->init.initiate_tag) != asoc->peer_vtag ||
|
||||
init_cp->init.initiate_tag == 0)) {
|
||||
/*
|
||||
* If nat support, and the below and stcb is established, send back
|
||||
* a ABORT(colliding state) if we are established.
|
||||
*/
|
||||
if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) &&
|
||||
(asoc->peer_supports_nat) &&
|
||||
((ntohl(initack_cp->init.initiate_tag) == asoc->my_vtag) &&
|
||||
((ntohl(init_cp->init.initiate_tag) != asoc->peer_vtag) ||
|
||||
(asoc->peer_vtag == 0)))) {
|
||||
/*
|
||||
* Special case - Peer's support nat. We may have two init's
|
||||
* that we gave out the same tag on since one was not
|
||||
* established.. i.e. we get INIT from host-1 behind the nat
|
||||
* and we respond tag-a, we get a INIT from host-2 behind
|
||||
* the nat and we get tag-a again. Then we bring up host-1
|
||||
* (or 2's) assoc, Then comes the cookie from hsot-2 (or 1).
|
||||
* Now we have colliding state. We must send an abort here
|
||||
* with colliding state indication.
|
||||
*/
|
||||
op_err = sctp_get_mbuf_for_msg(sizeof(struct sctp_paramhdr),
|
||||
0, M_DONTWAIT, 1, MT_DATA);
|
||||
if (op_err == NULL) {
|
||||
/* FOOBAR */
|
||||
return (NULL);
|
||||
}
|
||||
/* pre-reserve some space */
|
||||
#ifdef INET6
|
||||
SCTP_BUF_RESV_UF(op_err, sizeof(struct ip6_hdr));
|
||||
#else
|
||||
SCTP_BUF_RESV_UF(op_err, sizeof(struct ip));
|
||||
#endif
|
||||
SCTP_BUF_RESV_UF(op_err, sizeof(struct sctphdr));
|
||||
SCTP_BUF_RESV_UF(op_err, sizeof(struct sctp_chunkhdr));
|
||||
/* Set the len */
|
||||
SCTP_BUF_LEN(op_err) = sizeof(struct sctp_paramhdr);
|
||||
ph = mtod(op_err, struct sctp_paramhdr *);
|
||||
ph->param_type = htons(SCTP_CAUSE_NAT_COLLIDING_STATE);
|
||||
ph->param_length = htons(sizeof(struct sctp_paramhdr));
|
||||
sctp_send_abort(m, iphlen, sh, 0, op_err, vrf_id, port);
|
||||
return (NULL);
|
||||
}
|
||||
if ((ntohl(initack_cp->init.initiate_tag) == asoc->my_vtag) &&
|
||||
((ntohl(init_cp->init.initiate_tag) != asoc->peer_vtag) ||
|
||||
(asoc->peer_vtag == 0))) {
|
||||
/*
|
||||
* case B in Section 5.2.4 Table 2: MXAA or MOAA my info
|
||||
* should be ok, re-accept peer info
|
||||
@ -1612,6 +1780,17 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset,
|
||||
cookie->tie_tag_peer_vtag != 0) {
|
||||
struct sctpasochead *head;
|
||||
|
||||
if (asoc->peer_supports_nat) {
|
||||
/*
|
||||
* This is a gross gross hack. just call the
|
||||
* cookie_new code since we are allowing a duplicate
|
||||
* association. I hope this works...
|
||||
*/
|
||||
return (sctp_process_cookie_new(m, iphlen, offset, sh, cookie, cookie_len,
|
||||
inp, netp, init_src, notification,
|
||||
auth_skipped, auth_offset, auth_len,
|
||||
vrf_id, port));
|
||||
}
|
||||
/*
|
||||
* case A in Section 5.2.4 Table 2: XXMM (peer restarted)
|
||||
*/
|
||||
@ -1660,6 +1839,12 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset,
|
||||
memset(asoc->mapping_array, 0,
|
||||
asoc->mapping_array_size);
|
||||
}
|
||||
/* EY 05/13/08 - nr_sack version of the above if statement */
|
||||
if (asoc->nr_mapping_array && SCTP_BASE_SYSCTL(sctp_nr_sack_on_off)
|
||||
&& asoc->peer_supports_nr_sack) {
|
||||
memset(asoc->nr_mapping_array, 0,
|
||||
asoc->nr_mapping_array_size);
|
||||
}
|
||||
SCTP_TCB_UNLOCK(stcb);
|
||||
SCTP_INP_INFO_WLOCK();
|
||||
SCTP_INP_WLOCK(stcb->sctp_ep);
|
||||
@ -1689,14 +1874,6 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset,
|
||||
*/
|
||||
LIST_INSERT_HEAD(head, stcb, sctp_asocs);
|
||||
|
||||
/* Is this the first restart? */
|
||||
if (stcb->asoc.in_restart_hash == 0) {
|
||||
/* Ok add it to assoc_id vtag hash */
|
||||
head = &SCTP_BASE_INFO(sctp_restarthash)[SCTP_PCBHASH_ASOC(stcb->asoc.assoc_id,
|
||||
SCTP_BASE_INFO(hashrestartmark))];
|
||||
LIST_INSERT_HEAD(head, stcb, sctp_tcbrestarhash);
|
||||
stcb->asoc.in_restart_hash = 1;
|
||||
}
|
||||
/* process the INIT info (peer's info) */
|
||||
SCTP_TCB_SEND_UNLOCK(stcb);
|
||||
SCTP_INP_WUNLOCK(stcb->sctp_ep);
|
||||
@ -1746,7 +1923,7 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset,
|
||||
* cookie-echo chunk length: length of the cookie chunk to: where the init
|
||||
* was from returns a new TCB
|
||||
*/
|
||||
static struct sctp_tcb *
|
||||
struct sctp_tcb *
|
||||
sctp_process_cookie_new(struct mbuf *m, int iphlen, int offset,
|
||||
struct sctphdr *sh, struct sctp_state_cookie *cookie, int cookie_len,
|
||||
struct sctp_inpcb *inp, struct sctp_nets **netp,
|
||||
@ -1886,7 +2063,7 @@ sctp_process_cookie_new(struct mbuf *m, int iphlen, int offset,
|
||||
}
|
||||
/* process the INIT-ACK info (my info) */
|
||||
old_tag = asoc->my_vtag;
|
||||
asoc->assoc_id = asoc->my_vtag = ntohl(initack_cp->init.initiate_tag);
|
||||
asoc->my_vtag = ntohl(initack_cp->init.initiate_tag);
|
||||
asoc->my_rwnd = ntohl(initack_cp->init.a_rwnd);
|
||||
asoc->pre_open_streams = ntohs(initack_cp->init.num_outbound_streams);
|
||||
asoc->init_seq_number = ntohl(initack_cp->init.initial_tsn);
|
||||
@ -2089,6 +2266,18 @@ sctp_process_cookie_new(struct mbuf *m, int iphlen, int offset,
|
||||
return (stcb);
|
||||
}
|
||||
|
||||
/*
|
||||
* CODE LIKE THIS NEEDS TO RUN IF the peer supports the NAT extension, i.e
|
||||
* we NEED to make sure we are not already using the vtag. If so we
|
||||
* need to send back an ABORT-TRY-AGAIN-WITH-NEW-TAG No middle box bit!
|
||||
head = &SCTP_BASE_INFO(sctp_asochash)[SCTP_PCBHASH_ASOC(tag,
|
||||
SCTP_BASE_INFO(hashasocmark))];
|
||||
LIST_FOREACH(stcb, head, sctp_asocs) {
|
||||
if ((stcb->asoc.my_vtag == tag) && (stcb->rport == rport) && (inp == stcb->sctp_ep)) {
|
||||
-- SEND ABORT - TRY AGAIN --
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
* handles a COOKIE-ECHO message stcb: modified to either a new or left as
|
||||
@ -2422,8 +2611,8 @@ sctp_handle_cookie_echo(struct mbuf *m, int iphlen, int offset,
|
||||
/* this is abnormal... cookie-echo on existing TCB */
|
||||
had_a_existing_tcb = 1;
|
||||
*stcb = sctp_process_cookie_existing(m, iphlen, offset, sh,
|
||||
cookie, cookie_len, *inp_p, *stcb, *netp, to,
|
||||
¬ification, &sac_restart_id, vrf_id);
|
||||
cookie, cookie_len, *inp_p, *stcb, netp, to,
|
||||
¬ification, &sac_restart_id, vrf_id, auth_skipped, auth_offset, auth_len, port);
|
||||
}
|
||||
|
||||
if (*stcb == NULL) {
|
||||
@ -2544,8 +2733,6 @@ sctp_handle_cookie_echo(struct mbuf *m, int iphlen, int offset,
|
||||
sctp_free_chunklist(inp->sctp_ep.local_auth_chunks);
|
||||
inp->sctp_ep.local_auth_chunks =
|
||||
sctp_copy_chunklist((*inp_p)->sctp_ep.local_auth_chunks);
|
||||
(void)sctp_copy_skeylist(&(*inp_p)->sctp_ep.shared_keys,
|
||||
&inp->sctp_ep.shared_keys);
|
||||
|
||||
/*
|
||||
* Now we must move it from one hash table to
|
||||
@ -3040,6 +3227,10 @@ process_chunk_drop(struct sctp_tcb *stcb, struct sctp_chunk_desc *desc,
|
||||
/* resend the sack */
|
||||
sctp_send_sack(stcb);
|
||||
break;
|
||||
/* EY for nr_sacks */
|
||||
case SCTP_NR_SELECTIVE_ACK:
|
||||
sctp_send_nr_sack(stcb); /* EY resend the nr-sack */
|
||||
break;
|
||||
case SCTP_HEARTBEAT_REQUEST:
|
||||
/* resend a demand HB */
|
||||
if ((stcb->asoc.overall_error_count + 3) < stcb->asoc.max_send_times) {
|
||||
@ -3296,6 +3487,17 @@ sctp_handle_stream_reset_response(struct sctp_tcb *stcb,
|
||||
stcb->asoc.tsn_last_delivered = stcb->asoc.cumulative_tsn = stcb->asoc.highest_tsn_inside_map;
|
||||
stcb->asoc.mapping_array_base_tsn = ntohl(resp->senders_next_tsn);
|
||||
memset(stcb->asoc.mapping_array, 0, stcb->asoc.mapping_array_size);
|
||||
|
||||
/*
|
||||
* EY 05/13/08 - nr_sack: to keep
|
||||
* nr_mapping array be consistent
|
||||
* with mapping_array
|
||||
*/
|
||||
if (SCTP_BASE_SYSCTL(sctp_nr_sack_on_off) && stcb->asoc.peer_supports_nr_sack) {
|
||||
stcb->asoc.highest_tsn_inside_nr_map = stcb->asoc.highest_tsn_inside_map;
|
||||
stcb->asoc.nr_mapping_array_base_tsn = stcb->asoc.mapping_array_base_tsn;
|
||||
memset(stcb->asoc.nr_mapping_array, 0, stcb->asoc.nr_mapping_array_size);
|
||||
}
|
||||
stcb->asoc.sending_seq = ntohl(resp->receivers_next_tsn);
|
||||
stcb->asoc.last_acked_seq = stcb->asoc.cumulative_tsn;
|
||||
|
||||
@ -3402,6 +3604,15 @@ sctp_handle_str_reset_request_tsn(struct sctp_tcb *stcb,
|
||||
stcb->asoc.tsn_last_delivered = stcb->asoc.cumulative_tsn = stcb->asoc.highest_tsn_inside_map;
|
||||
stcb->asoc.mapping_array_base_tsn = stcb->asoc.highest_tsn_inside_map + 1;
|
||||
memset(stcb->asoc.mapping_array, 0, stcb->asoc.mapping_array_size);
|
||||
/*
|
||||
* EY 05/13/08 -nr_sack: to keep nr_mapping array consistent
|
||||
* with mapping array
|
||||
*/
|
||||
if (SCTP_BASE_SYSCTL(sctp_nr_sack_on_off) && stcb->asoc.peer_supports_nr_sack) {
|
||||
stcb->asoc.highest_tsn_inside_nr_map = stcb->asoc.highest_tsn_inside_map;
|
||||
stcb->asoc.nr_mapping_array_base_tsn = stcb->asoc.highest_tsn_inside_map + 1;
|
||||
memset(stcb->asoc.nr_mapping_array, 0, stcb->asoc.nr_mapping_array_size);
|
||||
}
|
||||
atomic_add_int(&stcb->asoc.sending_seq, 1);
|
||||
/* save off historical data for retrans */
|
||||
stcb->asoc.last_sending_seq[1] = stcb->asoc.last_sending_seq[0];
|
||||
@ -3940,7 +4151,7 @@ __attribute__((noinline))
|
||||
if (asconf_len < sizeof(struct sctp_asconf_paramhdr))
|
||||
break;
|
||||
stcb = sctp_findassociation_ep_asconf(m, iphlen,
|
||||
*offset, sh, &inp, netp);
|
||||
*offset, sh, &inp, netp, vrf_id);
|
||||
if (stcb != NULL)
|
||||
break;
|
||||
asconf_offset += SCTP_SIZE32(asconf_len);
|
||||
@ -4043,6 +4254,8 @@ __attribute__((noinline))
|
||||
* process all control chunks...
|
||||
*/
|
||||
if (((ch->chunk_type == SCTP_SELECTIVE_ACK) ||
|
||||
/* EY */
|
||||
(ch->chunk_type == SCTP_NR_SELECTIVE_ACK) ||
|
||||
(ch->chunk_type == SCTP_HEARTBEAT_REQUEST)) &&
|
||||
(SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_COOKIE_ECHOED)) {
|
||||
/* implied cookie-ack.. we must have lost the ack */
|
||||
@ -4328,6 +4541,11 @@ __attribute__((noinline))
|
||||
sctp_handle_sack(m, *offset,
|
||||
sack, stcb, *netp, &abort_now, chk_length, a_rwnd);
|
||||
}
|
||||
if (TAILQ_EMPTY(&stcb->asoc.send_queue) &&
|
||||
TAILQ_EMPTY(&stcb->asoc.sent_queue) &&
|
||||
(stcb->asoc.stream_queue_cnt == 0)) {
|
||||
sctp_ulp_notify(SCTP_NOTIFY_SENDER_DRY, stcb, 0, NULL, SCTP_SO_NOT_LOCKED);
|
||||
}
|
||||
if (abort_now) {
|
||||
/* ABORT signal from sack processing */
|
||||
*offset = length;
|
||||
@ -4335,6 +4553,102 @@ __attribute__((noinline))
|
||||
}
|
||||
}
|
||||
break;
|
||||
/*
|
||||
* EY - nr_sack: If the received chunk is an
|
||||
* nr_sack chunk
|
||||
*/
|
||||
case SCTP_NR_SELECTIVE_ACK:
|
||||
SCTPDBG(SCTP_DEBUG_INPUT3, "SCTP_NR_SACK\n");
|
||||
SCTP_STAT_INCR(sctps_recvsacks);
|
||||
{
|
||||
struct sctp_nr_sack_chunk *nr_sack;
|
||||
int abort_now = 0;
|
||||
uint32_t a_rwnd, cum_ack;
|
||||
uint16_t num_seg, num_nr_seg;
|
||||
int nonce_sum_flag, all_bit;
|
||||
|
||||
if ((stcb == NULL) || (chk_length < sizeof(struct sctp_nr_sack_chunk))) {
|
||||
SCTPDBG(SCTP_DEBUG_INDATA1, "Bad size on nr_sack chunk, too small\n");
|
||||
ignore_nr_sack:
|
||||
*offset = length;
|
||||
if (locked_tcb) {
|
||||
SCTP_TCB_UNLOCK(locked_tcb);
|
||||
}
|
||||
return (NULL);
|
||||
}
|
||||
/*
|
||||
* EY nr_sacks have not been negotiated but
|
||||
* the peer end sent an nr_sack, silently
|
||||
* discard the chunk
|
||||
*/
|
||||
if (!(SCTP_BASE_SYSCTL(sctp_nr_sack_on_off) && stcb->asoc.peer_supports_nr_sack)) {
|
||||
goto unknown_chunk;
|
||||
}
|
||||
if (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_SHUTDOWN_ACK_SENT) {
|
||||
/*-
|
||||
* If we have sent a shutdown-ack, we will pay no
|
||||
* attention to a sack sent in to us since
|
||||
* we don't care anymore.
|
||||
*/
|
||||
goto ignore_nr_sack;
|
||||
}
|
||||
nr_sack = (struct sctp_nr_sack_chunk *)ch;
|
||||
nonce_sum_flag = ch->chunk_flags & SCTP_SACK_NONCE_SUM;
|
||||
all_bit = ch->chunk_flags & SCTP_NR_SACK_ALL_BIT;
|
||||
|
||||
cum_ack = ntohl(nr_sack->nr_sack.cum_tsn_ack);
|
||||
num_seg = ntohs(nr_sack->nr_sack.num_gap_ack_blks);
|
||||
/*
|
||||
* EY -if All bit is set, then there are as
|
||||
* many gaps as nr_gaps
|
||||
*/
|
||||
if (all_bit) {
|
||||
num_seg = ntohs(nr_sack->nr_sack.num_nr_gap_ack_blks);
|
||||
}
|
||||
num_nr_seg = ntohs(nr_sack->nr_sack.num_nr_gap_ack_blks);
|
||||
a_rwnd = (uint32_t) ntohl(nr_sack->nr_sack.a_rwnd);
|
||||
SCTPDBG(SCTP_DEBUG_INPUT3, "SCTP_NR_SACK process cum_ack:%x num_seg:%d a_rwnd:%d\n",
|
||||
cum_ack,
|
||||
num_seg,
|
||||
a_rwnd
|
||||
);
|
||||
stcb->asoc.seen_a_sack_this_pkt = 1;
|
||||
if ((stcb->asoc.pr_sctp_cnt == 0) &&
|
||||
(num_seg == 0) &&
|
||||
((compare_with_wrap(cum_ack, stcb->asoc.last_acked_seq, MAX_TSN)) ||
|
||||
(cum_ack == stcb->asoc.last_acked_seq)) &&
|
||||
(stcb->asoc.saw_sack_with_frags == 0) &&
|
||||
(!TAILQ_EMPTY(&stcb->asoc.sent_queue))
|
||||
) {
|
||||
/*
|
||||
* We have a SIMPLE sack having no
|
||||
* prior segments and data on sent
|
||||
* queue to be acked.. Use the
|
||||
* faster path sack processing. We
|
||||
* also allow window update sacks
|
||||
* with no missing segments to go
|
||||
* this way too.
|
||||
*/
|
||||
sctp_express_handle_nr_sack(stcb, cum_ack, a_rwnd, nonce_sum_flag,
|
||||
&abort_now);
|
||||
} else {
|
||||
if (netp && *netp)
|
||||
sctp_handle_nr_sack(m, *offset,
|
||||
nr_sack, stcb, *netp, &abort_now, chk_length, a_rwnd);
|
||||
}
|
||||
if (TAILQ_EMPTY(&stcb->asoc.send_queue) &&
|
||||
TAILQ_EMPTY(&stcb->asoc.sent_queue) &&
|
||||
(stcb->asoc.stream_queue_cnt == 0)) {
|
||||
sctp_ulp_notify(SCTP_NOTIFY_SENDER_DRY, stcb, 0, NULL, SCTP_SO_NOT_LOCKED);
|
||||
}
|
||||
if (abort_now) {
|
||||
/* ABORT signal from sack processing */
|
||||
*offset = length;
|
||||
return (NULL);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case SCTP_HEARTBEAT_REQUEST:
|
||||
SCTPDBG(SCTP_DEBUG_INPUT3, "SCTP_HEARTBEAT\n");
|
||||
if ((stcb) && netp && *netp) {
|
||||
@ -5242,6 +5556,18 @@ sctp_common_input_processing(struct mbuf **mm, int iphlen, int offset,
|
||||
return;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static void
|
||||
sctp_print_mbuf_chain(struct mbuf *m)
|
||||
{
|
||||
for (; m; m = SCTP_BUF_NEXT(m)) {
|
||||
printf("%p: m_len = %ld\n", m, SCTP_BUF_LEN(m));
|
||||
if (SCTP_BUF_IS_EXTENDED(m))
|
||||
printf("%p: extend_size = %d\n", m, SCTP_BUF_EXTEND_SIZE(m));
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void
|
||||
sctp_input_with_port(i_pak, off, port)
|
||||
|
@ -500,3 +500,24 @@ sctp_get_mbuf_for_msg(unsigned int space_needed,
|
||||
#define MD5_Final MD5Final
|
||||
|
||||
#endif
|
||||
|
||||
#define SCTP_DECREMENT_AND_CHECK_REFCOUNT(addr) (atomic_fetchadd_int(addr, -1) == 1)
|
||||
#if defined(INVARIANTS)
|
||||
#define SCTP_SAVE_ATOMIC_DECREMENT(addr, val) \
|
||||
{ \
|
||||
int32_t oldval; \
|
||||
oldval = atomic_fetchadd_int(addr, -val); \
|
||||
if (oldval < val) { \
|
||||
panic("Counter goes negative"); \
|
||||
} \
|
||||
}
|
||||
#else
|
||||
#define SCTP_SAVE_ATOMIC_DECREMENT(addr, val) \
|
||||
{ \
|
||||
int32_t oldval; \
|
||||
oldval = atomic_fetchadd_int(addr, -val); \
|
||||
if (oldval < val) { \
|
||||
*addr = 0; \
|
||||
} \
|
||||
}
|
||||
#endif
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -88,7 +88,7 @@ sctp_send_initiate_ack(struct sctp_inpcb *, struct sctp_tcb *,
|
||||
|
||||
struct mbuf *
|
||||
sctp_arethere_unrecognized_parameters(struct mbuf *, int, int *,
|
||||
struct sctp_chunkhdr *);
|
||||
struct sctp_chunkhdr *, int *);
|
||||
void sctp_queue_op_err(struct sctp_tcb *, struct mbuf *);
|
||||
|
||||
int
|
||||
@ -150,6 +150,9 @@ void send_forward_tsn(struct sctp_tcb *, struct sctp_association *);
|
||||
|
||||
void sctp_send_sack(struct sctp_tcb *);
|
||||
|
||||
/* EY 05/07/08 if nr_sacks used, the following function will be called instead of sctp_send_sack */
|
||||
void sctp_send_nr_sack(struct sctp_tcb *);
|
||||
|
||||
int sctp_send_hb(struct sctp_tcb *, int, struct sctp_nets *);
|
||||
|
||||
void sctp_send_ecn_echo(struct sctp_tcb *, struct sctp_nets *, uint32_t);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*-
|
||||
* Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved.
|
||||
* Copyright (c) 2001-2008, by 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:
|
||||
@ -226,10 +226,7 @@ sctp_find_vrf(uint32_t vrf_id)
|
||||
void
|
||||
sctp_free_vrf(struct sctp_vrf *vrf)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = atomic_fetchadd_int(&vrf->refcount, -1);
|
||||
if (ret == 1) {
|
||||
if (SCTP_DECREMENT_AND_CHECK_REFCOUNT(&vrf->refcount)) {
|
||||
if (vrf->vrf_addr_hash) {
|
||||
SCTP_HASH_FREE(vrf->vrf_addr_hash, vrf->vrf_addr_hashmark);
|
||||
vrf->vrf_addr_hash = NULL;
|
||||
@ -244,10 +241,7 @@ sctp_free_vrf(struct sctp_vrf *vrf)
|
||||
void
|
||||
sctp_free_ifn(struct sctp_ifn *sctp_ifnp)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = atomic_fetchadd_int(&sctp_ifnp->refcount, -1);
|
||||
if (ret == 1) {
|
||||
if (SCTP_DECREMENT_AND_CHECK_REFCOUNT(&sctp_ifnp->refcount)) {
|
||||
/* We zero'd the count */
|
||||
if (sctp_ifnp->vrf) {
|
||||
sctp_free_vrf(sctp_ifnp->vrf);
|
||||
@ -272,10 +266,7 @@ sctp_update_ifn_mtu(uint32_t ifn_index, uint32_t mtu)
|
||||
void
|
||||
sctp_free_ifa(struct sctp_ifa *sctp_ifap)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = atomic_fetchadd_int(&sctp_ifap->refcount, -1);
|
||||
if (ret == 1) {
|
||||
if (SCTP_DECREMENT_AND_CHECK_REFCOUNT(&sctp_ifap->refcount)) {
|
||||
/* We zero'd the count */
|
||||
if (sctp_ifap->ifn_p) {
|
||||
sctp_free_ifn(sctp_ifap->ifn_p);
|
||||
@ -1295,7 +1286,7 @@ sctp_findassociation_ep_addr(struct sctp_inpcb **inp_p, struct sockaddr *remote,
|
||||
*/
|
||||
|
||||
struct sctp_tcb *
|
||||
sctp_findassociation_ep_asocid(struct sctp_inpcb *inp, sctp_assoc_t asoc_id, int want_lock)
|
||||
sctp_findasoc_ep_asocid_locked(struct sctp_inpcb *inp, sctp_assoc_t asoc_id, int want_lock)
|
||||
{
|
||||
/*
|
||||
* Use my the assoc_id to find a endpoint
|
||||
@ -1304,33 +1295,29 @@ sctp_findassociation_ep_asocid(struct sctp_inpcb *inp, sctp_assoc_t asoc_id, int
|
||||
struct sctp_tcb *stcb;
|
||||
uint32_t id;
|
||||
|
||||
if (asoc_id == 0 || inp == NULL) {
|
||||
if (inp == NULL) {
|
||||
SCTP_PRINTF("TSNH ep_associd\n");
|
||||
return (NULL);
|
||||
}
|
||||
if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) {
|
||||
SCTP_PRINTF("TSNH ep_associd0\n");
|
||||
return (NULL);
|
||||
}
|
||||
SCTP_INP_INFO_RLOCK();
|
||||
id = (uint32_t) asoc_id;
|
||||
head = &SCTP_BASE_INFO(sctp_asochash)[SCTP_PCBHASH_ASOC(id,
|
||||
SCTP_BASE_INFO(hashasocmark))];
|
||||
head = &inp->sctp_asocidhash[SCTP_PCBHASH_ASOC(id, inp->hashasocidmark)];
|
||||
if (head == NULL) {
|
||||
/* invalid id TSNH */
|
||||
SCTP_INP_INFO_RUNLOCK();
|
||||
SCTP_PRINTF("TSNH ep_associd1\n");
|
||||
return (NULL);
|
||||
}
|
||||
LIST_FOREACH(stcb, head, sctp_asocs) {
|
||||
SCTP_INP_RLOCK(stcb->sctp_ep);
|
||||
if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) {
|
||||
SCTP_INP_RUNLOCK(stcb->sctp_ep);
|
||||
SCTP_INP_INFO_RUNLOCK();
|
||||
return (NULL);
|
||||
}
|
||||
LIST_FOREACH(stcb, head, sctp_tcbasocidhash) {
|
||||
if (stcb->asoc.assoc_id == id) {
|
||||
/* candidate */
|
||||
if (inp != stcb->sctp_ep) {
|
||||
/*
|
||||
* some other guy has the same id active (id
|
||||
* collision ??).
|
||||
*/
|
||||
SCTP_INP_RUNLOCK(stcb->sctp_ep);
|
||||
SCTP_PRINTF("TSNH ep_associd2\n");
|
||||
continue;
|
||||
}
|
||||
if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) {
|
||||
@ -1339,58 +1326,25 @@ sctp_findassociation_ep_asocid(struct sctp_inpcb *inp, sctp_assoc_t asoc_id, int
|
||||
if (want_lock) {
|
||||
SCTP_TCB_LOCK(stcb);
|
||||
}
|
||||
SCTP_INP_RUNLOCK(stcb->sctp_ep);
|
||||
SCTP_INP_INFO_RUNLOCK();
|
||||
return (stcb);
|
||||
}
|
||||
SCTP_INP_RUNLOCK(stcb->sctp_ep);
|
||||
}
|
||||
/* Ok if we missed here, lets try the restart hash */
|
||||
head = &SCTP_BASE_INFO(sctp_restarthash)[SCTP_PCBHASH_ASOC(id, SCTP_BASE_INFO(hashrestartmark))];
|
||||
if (head == NULL) {
|
||||
/* invalid id TSNH */
|
||||
SCTP_INP_INFO_RUNLOCK();
|
||||
return (NULL);
|
||||
}
|
||||
LIST_FOREACH(stcb, head, sctp_tcbrestarhash) {
|
||||
SCTP_INP_RLOCK(stcb->sctp_ep);
|
||||
if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) {
|
||||
SCTP_INP_RUNLOCK(stcb->sctp_ep);
|
||||
continue;
|
||||
}
|
||||
if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) {
|
||||
continue;
|
||||
}
|
||||
if (want_lock) {
|
||||
SCTP_TCB_LOCK(stcb);
|
||||
}
|
||||
if (stcb->asoc.assoc_id == id) {
|
||||
/* candidate */
|
||||
SCTP_INP_RUNLOCK(stcb->sctp_ep);
|
||||
if (inp != stcb->sctp_ep) {
|
||||
/*
|
||||
* some other guy has the same id active (id
|
||||
* collision ??).
|
||||
*/
|
||||
if (want_lock) {
|
||||
SCTP_TCB_UNLOCK(stcb);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
SCTP_INP_INFO_RUNLOCK();
|
||||
return (stcb);
|
||||
} else {
|
||||
SCTP_INP_RUNLOCK(stcb->sctp_ep);
|
||||
}
|
||||
if (want_lock) {
|
||||
SCTP_TCB_UNLOCK(stcb);
|
||||
}
|
||||
}
|
||||
SCTP_INP_INFO_RUNLOCK();
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
|
||||
struct sctp_tcb *
|
||||
sctp_findassociation_ep_asocid(struct sctp_inpcb *inp, sctp_assoc_t asoc_id, int want_lock)
|
||||
{
|
||||
struct sctp_tcb *stcb;
|
||||
|
||||
SCTP_INP_RLOCK(inp);
|
||||
stcb = sctp_findasoc_ep_asocid_locked(inp, asoc_id, want_lock);
|
||||
SCTP_INP_RUNLOCK(inp);
|
||||
return (stcb);
|
||||
}
|
||||
|
||||
|
||||
static struct sctp_inpcb *
|
||||
sctp_endpoint_probe(struct sockaddr *nam, struct sctppcbhead *head,
|
||||
uint16_t lport, uint32_t vrf_id)
|
||||
@ -1434,6 +1388,7 @@ sctp_endpoint_probe(struct sockaddr *nam, struct sctppcbhead *head,
|
||||
|
||||
if (head == NULL)
|
||||
return (NULL);
|
||||
|
||||
LIST_FOREACH(inp, head, sctp_hash) {
|
||||
SCTP_INP_RLOCK(inp);
|
||||
if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) {
|
||||
@ -1695,8 +1650,11 @@ sctp_pcb_findep(struct sockaddr *nam, int find_tcp_pool, int have_lock,
|
||||
* If the TCP model exists it could be that the main listening
|
||||
* endpoint is gone but there exists a connected socket for this guy
|
||||
* yet. If so we can return the first one that we find. This may NOT
|
||||
* be the correct one but the sctp_findassociation_ep_addr has
|
||||
* further code to look at all TCP models.
|
||||
* be the correct one so the caller should be wary on the return
|
||||
* INP. Currently the onlyc caller that sets this flag is in bindx
|
||||
* where we are verifying that a user CAN bind the address. He
|
||||
* either has bound it already, or someone else has, or its open to
|
||||
* bind, so this is good enough.
|
||||
*/
|
||||
if (inp == NULL && find_tcp_pool) {
|
||||
head = &SCTP_BASE_INFO(sctp_tcpephash)[SCTP_PCBHASH_ALLADDR(lport, SCTP_BASE_INFO(hashtcpmark))];
|
||||
@ -1844,11 +1802,67 @@ sctp_findassociation_special_addr(struct mbuf *m, int iphlen, int offset,
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
static int
|
||||
sctp_does_stcb_own_this_addr(struct sctp_tcb *stcb, struct sockaddr *to)
|
||||
{
|
||||
struct sctp_nets *net;
|
||||
|
||||
/*
|
||||
* Simple question, the ports match, does the tcb own the to
|
||||
* address?
|
||||
*/
|
||||
if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL)) {
|
||||
/* of course */
|
||||
return (1);
|
||||
}
|
||||
/* have to look at all bound addresses */
|
||||
TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
|
||||
if (net->ro._l_addr.sa.sa_family != to->sa_family) {
|
||||
/* not the same family, can't be a match */
|
||||
continue;
|
||||
}
|
||||
switch (to->sa_family) {
|
||||
case AF_INET:
|
||||
{
|
||||
struct sockaddr_in *sin, *rsin;
|
||||
|
||||
sin = (struct sockaddr_in *)&net->ro._l_addr;
|
||||
rsin = (struct sockaddr_in *)to;
|
||||
if (sin->sin_addr.s_addr ==
|
||||
rsin->sin_addr.s_addr) {
|
||||
/* found it */
|
||||
return (1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
#ifdef INET6
|
||||
case AF_INET6:
|
||||
{
|
||||
struct sockaddr_in6 *sin6, *rsin6;
|
||||
|
||||
sin6 = (struct sockaddr_in6 *)&net->ro._l_addr;
|
||||
rsin6 = (struct sockaddr_in6 *)to;
|
||||
if (SCTP6_ARE_ADDR_EQUAL(sin6,
|
||||
rsin6)) {
|
||||
/* Update the endpoint pointer */
|
||||
return (1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
default:
|
||||
/* TSNH */
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* Nope, do not have the address ;-( */
|
||||
return (0);
|
||||
}
|
||||
|
||||
static struct sctp_tcb *
|
||||
sctp_findassoc_by_vtag(struct sockaddr *from, uint32_t vtag,
|
||||
sctp_findassoc_by_vtag(struct sockaddr *from, struct sockaddr *to, uint32_t vtag,
|
||||
struct sctp_inpcb **inp_p, struct sctp_nets **netp, uint16_t rport,
|
||||
uint16_t lport, int skip_src_check)
|
||||
uint16_t lport, int skip_src_check, uint32_t vrf_id, uint32_t remote_tag)
|
||||
{
|
||||
/*
|
||||
* Use my vtag to hash. If we find it we then verify the source addr
|
||||
@ -1880,18 +1894,10 @@ sctp_findassoc_by_vtag(struct sockaddr *from, uint32_t vtag,
|
||||
if (stcb->asoc.my_vtag == vtag) {
|
||||
/* candidate */
|
||||
if (stcb->rport != rport) {
|
||||
/*
|
||||
* we could remove this if vtags are unique
|
||||
* across the system.
|
||||
*/
|
||||
SCTP_TCB_UNLOCK(stcb);
|
||||
continue;
|
||||
}
|
||||
if (stcb->sctp_ep->sctp_lport != lport) {
|
||||
/*
|
||||
* we could remove this if vtags are unique
|
||||
* across the system.
|
||||
*/
|
||||
SCTP_TCB_UNLOCK(stcb);
|
||||
continue;
|
||||
}
|
||||
@ -1899,8 +1905,33 @@ sctp_findassoc_by_vtag(struct sockaddr *from, uint32_t vtag,
|
||||
SCTP_TCB_UNLOCK(stcb);
|
||||
continue;
|
||||
}
|
||||
/* RRS:Need toaddr check here */
|
||||
if (sctp_does_stcb_own_this_addr(stcb, to) == 0) {
|
||||
/* Endpoint does not own this address */
|
||||
SCTP_TCB_UNLOCK(stcb);
|
||||
continue;
|
||||
}
|
||||
if (remote_tag) {
|
||||
/*
|
||||
* If we have both vtags thats all we match
|
||||
* on
|
||||
*/
|
||||
if (stcb->asoc.peer_vtag == remote_tag) {
|
||||
/*
|
||||
* If both tags match we consider it
|
||||
* conclusive and check NO
|
||||
* source/destination addresses
|
||||
*/
|
||||
goto conclusive;
|
||||
}
|
||||
}
|
||||
if (skip_src_check) {
|
||||
*netp = NULL; /* unknown */
|
||||
conclusive:
|
||||
if (from) {
|
||||
net = sctp_findnet(stcb, from);
|
||||
} else {
|
||||
*netp = NULL; /* unknown */
|
||||
}
|
||||
if (inp_p)
|
||||
*inp_p = stcb->sctp_ep;
|
||||
SCTP_INP_INFO_RUNLOCK();
|
||||
@ -1985,14 +2016,8 @@ sctp_findassociation_addr(struct mbuf *m, int iphlen, int offset,
|
||||
/* Currently not supported. */
|
||||
return (NULL);
|
||||
}
|
||||
if (sh->v_tag) {
|
||||
/* we only go down this path if vtag is non-zero */
|
||||
retval = sctp_findassoc_by_vtag(from, ntohl(sh->v_tag),
|
||||
inp_p, netp, sh->src_port, sh->dest_port, 0);
|
||||
if (retval) {
|
||||
return (retval);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
switch (iph->ip_v) {
|
||||
case IPVERSION:
|
||||
{
|
||||
@ -2032,6 +2057,14 @@ sctp_findassociation_addr(struct mbuf *m, int iphlen, int offset,
|
||||
/* TSNH */
|
||||
break;
|
||||
}
|
||||
if (sh->v_tag) {
|
||||
/* we only go down this path if vtag is non-zero */
|
||||
retval = sctp_findassoc_by_vtag(from, to, ntohl(sh->v_tag),
|
||||
inp_p, netp, sh->src_port, sh->dest_port, 0, vrf_id, 0);
|
||||
if (retval) {
|
||||
return (retval);
|
||||
}
|
||||
}
|
||||
find_tcp_pool = 0;
|
||||
if ((ch->chunk_type != SCTP_INITIATION) &&
|
||||
(ch->chunk_type != SCTP_INITIATION_ACK) &&
|
||||
@ -2084,7 +2117,7 @@ sctp_findassociation_addr(struct mbuf *m, int iphlen, int offset,
|
||||
*/
|
||||
struct sctp_tcb *
|
||||
sctp_findassociation_ep_asconf(struct mbuf *m, int iphlen, int offset,
|
||||
struct sctphdr *sh, struct sctp_inpcb **inp_p, struct sctp_nets **netp)
|
||||
struct sctphdr *sh, struct sctp_inpcb **inp_p, struct sctp_nets **netp, uint32_t vrf_id)
|
||||
{
|
||||
struct sctp_tcb *stcb;
|
||||
struct sockaddr_in *sin;
|
||||
@ -2094,6 +2127,7 @@ sctp_findassociation_ep_asconf(struct mbuf *m, int iphlen, int offset,
|
||||
|
||||
#endif
|
||||
struct sockaddr_storage local_store, remote_store;
|
||||
struct sockaddr *to;
|
||||
struct ip *iph;
|
||||
|
||||
#ifdef INET6
|
||||
@ -2107,7 +2141,7 @@ sctp_findassociation_ep_asconf(struct mbuf *m, int iphlen, int offset,
|
||||
|
||||
memset(&local_store, 0, sizeof(local_store));
|
||||
memset(&remote_store, 0, sizeof(remote_store));
|
||||
|
||||
to = (struct sockaddr *)&local_store;
|
||||
/* First get the destination address setup too. */
|
||||
iph = mtod(m, struct ip *);
|
||||
switch (iph->ip_v) {
|
||||
@ -2202,8 +2236,8 @@ sctp_findassociation_ep_asconf(struct mbuf *m, int iphlen, int offset,
|
||||
}
|
||||
|
||||
if (zero_address) {
|
||||
stcb = sctp_findassoc_by_vtag(NULL, ntohl(sh->v_tag), inp_p,
|
||||
netp, sh->src_port, sh->dest_port, 1);
|
||||
stcb = sctp_findassoc_by_vtag(NULL, to, ntohl(sh->v_tag), inp_p,
|
||||
netp, sh->src_port, sh->dest_port, 1, vrf_id, 0);
|
||||
/*
|
||||
* printf("findassociation_ep_asconf: zero lookup address
|
||||
* finds stcb 0x%x\n", (uint32_t)stcb);
|
||||
@ -2211,7 +2245,7 @@ sctp_findassociation_ep_asconf(struct mbuf *m, int iphlen, int offset,
|
||||
} else {
|
||||
stcb = sctp_findassociation_ep_addr(inp_p,
|
||||
(struct sockaddr *)&remote_store, netp,
|
||||
(struct sockaddr *)&local_store, NULL);
|
||||
to, NULL);
|
||||
}
|
||||
return (stcb);
|
||||
}
|
||||
@ -2256,10 +2290,16 @@ sctp_inpcb_alloc(struct socket *so, uint32_t vrf_id)
|
||||
/* setup socket pointers */
|
||||
inp->sctp_socket = so;
|
||||
inp->ip_inp.inp.inp_socket = so;
|
||||
|
||||
inp->sctp_associd_counter = 1;
|
||||
inp->partial_delivery_point = SCTP_SB_LIMIT_RCV(so) >> SCTP_PARTIAL_DELIVERY_SHIFT;
|
||||
inp->sctp_frag_point = SCTP_DEFAULT_MAXSEGMENT;
|
||||
|
||||
/* init the small hash table we use to track asocid <-> tcb */
|
||||
inp->sctp_asocidhash = SCTP_HASH_INIT(SCTP_STACK_VTAG_HASH_SIZE, &inp->hashasocidmark);
|
||||
if (inp->sctp_asocidhash == NULL) {
|
||||
SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_ep), inp);
|
||||
SCTP_INP_INFO_WUNLOCK();
|
||||
return error;
|
||||
}
|
||||
#ifdef IPSEC
|
||||
{
|
||||
struct inpcbpolicy *pcb_sp = NULL;
|
||||
@ -2597,8 +2637,9 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr *addr,
|
||||
sin = (struct sockaddr_in *)addr;
|
||||
lport = sin->sin_port;
|
||||
/*
|
||||
* For LOOPBACK the prison_local_ip4() call will transmute the ip address
|
||||
* to the proper value.
|
||||
* For LOOPBACK the prison_local_ip4() call
|
||||
* will transmute the ip address to the
|
||||
* proper value.
|
||||
*/
|
||||
if (p && prison_local_ip4(p->td_ucred, &sin->sin_addr) != 0) {
|
||||
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EINVAL);
|
||||
@ -2627,8 +2668,9 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr *addr,
|
||||
lport = sin6->sin6_port;
|
||||
|
||||
/*
|
||||
* For LOOPBACK the prison_local_ip6() call will transmute the ipv6 address
|
||||
* to the proper value.
|
||||
* For LOOPBACK the prison_local_ip6() call
|
||||
* will transmute the ipv6 address to the
|
||||
* proper value.
|
||||
*/
|
||||
if (p && prison_local_ip6(p->td_ucred, &sin6->sin6_addr,
|
||||
(SCTP_IPV6_V6ONLY(inp) != 0)) != 0) {
|
||||
@ -3373,6 +3415,10 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from)
|
||||
(void)SCTP_OS_TIMER_STOP(&inp->sctp_ep.signature_change.timer);
|
||||
inp->sctp_ep.signature_change.type = SCTP_TIMER_TYPE_NONE;
|
||||
/* Clear the read queue */
|
||||
if ((inp->sctp_asocidhash) != NULL) {
|
||||
SCTP_HASH_FREE(inp->sctp_asocidhash, inp->hashasocidmark);
|
||||
inp->sctp_asocidhash = NULL;
|
||||
}
|
||||
/* sa_ignore FREED_MEMORY */
|
||||
while ((sq = TAILQ_FIRST(&inp->read_queue)) != NULL) {
|
||||
/* Its only abandoned if it had data left */
|
||||
@ -3864,6 +3910,32 @@ sctp_add_remote_addr(struct sctp_tcb *stcb, struct sockaddr *newaddr,
|
||||
}
|
||||
|
||||
|
||||
static uint32_t
|
||||
sctp_aloc_a_assoc_id(struct sctp_inpcb *inp, struct sctp_tcb *stcb)
|
||||
{
|
||||
uint32_t id;
|
||||
struct sctpasochead *head;
|
||||
struct sctp_tcb *lstcb;
|
||||
|
||||
try_again:
|
||||
if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) {
|
||||
/* TSNH */
|
||||
return (0);
|
||||
}
|
||||
SCTP_INP_WLOCK(inp);
|
||||
id = inp->sctp_associd_counter;
|
||||
inp->sctp_associd_counter++;
|
||||
lstcb = sctp_findasoc_ep_asocid_locked(inp, (sctp_assoc_t) id, 0);
|
||||
if (lstcb) {
|
||||
goto try_again;
|
||||
}
|
||||
head = &inp->sctp_asocidhash[SCTP_PCBHASH_ASOC(id, inp->hashasocidmark)];
|
||||
LIST_INSERT_HEAD(head, stcb, sctp_tcbasocidhash);
|
||||
stcb->asoc.in_asocid_hash = 1;
|
||||
SCTP_INP_WUNLOCK(inp);
|
||||
return id;
|
||||
}
|
||||
|
||||
/*
|
||||
* allocate an association and add it to the endpoint. The caller must be
|
||||
* careful to add all additional addresses once they are know right away or
|
||||
@ -3983,8 +4055,11 @@ sctp_aloc_assoc(struct sctp_inpcb *inp, struct sockaddr *firstaddr,
|
||||
|
||||
bzero(stcb, sizeof(*stcb));
|
||||
asoc = &stcb->asoc;
|
||||
|
||||
asoc->assoc_id = sctp_aloc_a_assoc_id(inp, stcb);
|
||||
SCTP_TCB_LOCK_INIT(stcb);
|
||||
SCTP_TCB_SEND_LOCK_INIT(stcb);
|
||||
stcb->rport = rport;
|
||||
/* setup back pointer's */
|
||||
stcb->sctp_ep = inp;
|
||||
stcb->sctp_socket = inp->sctp_socket;
|
||||
@ -3992,19 +4067,20 @@ sctp_aloc_assoc(struct sctp_inpcb *inp, struct sockaddr *firstaddr,
|
||||
/* failed */
|
||||
SCTP_TCB_LOCK_DESTROY(stcb);
|
||||
SCTP_TCB_SEND_LOCK_DESTROY(stcb);
|
||||
LIST_REMOVE(stcb, sctp_tcbasocidhash);
|
||||
SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_asoc), stcb);
|
||||
SCTP_DECR_ASOC_COUNT();
|
||||
*error = err;
|
||||
return (NULL);
|
||||
}
|
||||
/* and the port */
|
||||
stcb->rport = rport;
|
||||
SCTP_INP_INFO_WLOCK();
|
||||
SCTP_INP_WLOCK(inp);
|
||||
if (inp->sctp_flags & (SCTP_PCB_FLAGS_SOCKET_GONE | SCTP_PCB_FLAGS_SOCKET_ALLGONE)) {
|
||||
/* inpcb freed while alloc going on */
|
||||
SCTP_TCB_LOCK_DESTROY(stcb);
|
||||
SCTP_TCB_SEND_LOCK_DESTROY(stcb);
|
||||
LIST_REMOVE(stcb, sctp_tcbasocidhash);
|
||||
SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_asoc), stcb);
|
||||
SCTP_INP_WUNLOCK(inp);
|
||||
SCTP_INP_INFO_WUNLOCK();
|
||||
@ -4016,12 +4092,12 @@ sctp_aloc_assoc(struct sctp_inpcb *inp, struct sockaddr *firstaddr,
|
||||
SCTP_TCB_LOCK(stcb);
|
||||
|
||||
/* now that my_vtag is set, add it to the hash */
|
||||
head = &SCTP_BASE_INFO(sctp_asochash)[SCTP_PCBHASH_ASOC(stcb->asoc.my_vtag,
|
||||
SCTP_BASE_INFO(hashasocmark))];
|
||||
head = &SCTP_BASE_INFO(sctp_asochash)[SCTP_PCBHASH_ASOC(stcb->asoc.my_vtag, SCTP_BASE_INFO(hashasocmark))];
|
||||
/* put it in the bucket in the vtag hash of assoc's for the system */
|
||||
LIST_INSERT_HEAD(head, stcb, sctp_asocs);
|
||||
sctp_delete_from_timewait(stcb->asoc.my_vtag);
|
||||
|
||||
#ifdef MICHAELS_EXPERIMENT
|
||||
sctp_delete_from_timewait(stcb->asoc.my_vtag, inp->sctp_lport, stcb->rport);
|
||||
#endif
|
||||
SCTP_INP_INFO_WUNLOCK();
|
||||
|
||||
if ((err = sctp_add_remote_addr(stcb, firstaddr, SCTP_DO_SETSCOPE, SCTP_ALLOC_ASOC))) {
|
||||
@ -4037,6 +4113,7 @@ sctp_aloc_assoc(struct sctp_inpcb *inp, struct sockaddr *firstaddr,
|
||||
SCTP_DECR_ASOC_COUNT();
|
||||
SCTP_TCB_LOCK_DESTROY(stcb);
|
||||
SCTP_TCB_SEND_LOCK_DESTROY(stcb);
|
||||
LIST_REMOVE(stcb, sctp_tcbasocidhash);
|
||||
SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_asoc), stcb);
|
||||
SCTP_INP_WUNLOCK(inp);
|
||||
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, ENOBUFS);
|
||||
@ -4159,7 +4236,7 @@ sctp_del_remote_addr(struct sctp_tcb *stcb, struct sockaddr *remaddr)
|
||||
}
|
||||
|
||||
void
|
||||
sctp_delete_from_timewait(uint32_t tag)
|
||||
sctp_delete_from_timewait(uint32_t tag, uint16_t lport, uint16_t rport)
|
||||
{
|
||||
struct sctpvtaghead *chain;
|
||||
struct sctp_tagblock *twait_block;
|
||||
@ -4170,9 +4247,13 @@ sctp_delete_from_timewait(uint32_t tag)
|
||||
if (!SCTP_LIST_EMPTY(chain)) {
|
||||
LIST_FOREACH(twait_block, chain, sctp_nxt_tagblock) {
|
||||
for (i = 0; i < SCTP_NUMBER_IN_VTAG_BLOCK; i++) {
|
||||
if (twait_block->vtag_block[i].v_tag == tag) {
|
||||
if ((twait_block->vtag_block[i].v_tag == tag) &&
|
||||
(twait_block->vtag_block[i].lport == lport) &&
|
||||
(twait_block->vtag_block[i].rport == rport)) {
|
||||
twait_block->vtag_block[i].tv_sec_at_expire = 0;
|
||||
twait_block->vtag_block[i].v_tag = 0;
|
||||
twait_block->vtag_block[i].lport = 0;
|
||||
twait_block->vtag_block[i].rport = 0;
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
@ -4184,7 +4265,7 @@ sctp_delete_from_timewait(uint32_t tag)
|
||||
}
|
||||
|
||||
int
|
||||
sctp_is_in_timewait(uint32_t tag)
|
||||
sctp_is_in_timewait(uint32_t tag, uint16_t lport, uint16_t rport)
|
||||
{
|
||||
struct sctpvtaghead *chain;
|
||||
struct sctp_tagblock *twait_block;
|
||||
@ -4196,7 +4277,9 @@ sctp_is_in_timewait(uint32_t tag)
|
||||
if (!SCTP_LIST_EMPTY(chain)) {
|
||||
LIST_FOREACH(twait_block, chain, sctp_nxt_tagblock) {
|
||||
for (i = 0; i < SCTP_NUMBER_IN_VTAG_BLOCK; i++) {
|
||||
if (twait_block->vtag_block[i].v_tag == tag) {
|
||||
if ((twait_block->vtag_block[i].v_tag == tag) &&
|
||||
(twait_block->vtag_block[i].lport == lport) &&
|
||||
(twait_block->vtag_block[i].rport == rport)) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
@ -4211,7 +4294,7 @@ sctp_is_in_timewait(uint32_t tag)
|
||||
|
||||
|
||||
void
|
||||
sctp_add_vtag_to_timewait(uint32_t tag, uint32_t time)
|
||||
sctp_add_vtag_to_timewait(uint32_t tag, uint32_t time, uint16_t lport, uint16_t rport)
|
||||
{
|
||||
struct sctpvtaghead *chain;
|
||||
struct sctp_tagblock *twait_block;
|
||||
@ -4230,16 +4313,22 @@ sctp_add_vtag_to_timewait(uint32_t tag, uint32_t time)
|
||||
twait_block->vtag_block[i].tv_sec_at_expire =
|
||||
now.tv_sec + time;
|
||||
twait_block->vtag_block[i].v_tag = tag;
|
||||
twait_block->vtag_block[i].lport = lport;
|
||||
twait_block->vtag_block[i].rport = rport;
|
||||
set = 1;
|
||||
} else if ((twait_block->vtag_block[i].v_tag) &&
|
||||
((long)twait_block->vtag_block[i].tv_sec_at_expire < now.tv_sec)) {
|
||||
/* Audit expires this guy */
|
||||
twait_block->vtag_block[i].tv_sec_at_expire = 0;
|
||||
twait_block->vtag_block[i].v_tag = 0;
|
||||
twait_block->vtag_block[i].lport = 0;
|
||||
twait_block->vtag_block[i].rport = 0;
|
||||
if (set == 0) {
|
||||
/* Reuse it for my new tag */
|
||||
twait_block->vtag_block[i].tv_sec_at_expire = now.tv_sec + time;
|
||||
twait_block->vtag_block[i].v_tag = tag;
|
||||
twait_block->vtag_block[i].lport = lport;
|
||||
twait_block->vtag_block[i].rport = rport;
|
||||
set = 1;
|
||||
}
|
||||
}
|
||||
@ -4267,6 +4356,8 @@ sctp_add_vtag_to_timewait(uint32_t tag, uint32_t time)
|
||||
LIST_INSERT_HEAD(chain, twait_block, sctp_nxt_tagblock);
|
||||
twait_block->vtag_block[0].tv_sec_at_expire = now.tv_sec + time;
|
||||
twait_block->vtag_block[0].v_tag = tag;
|
||||
twait_block->vtag_block[0].lport = lport;
|
||||
twait_block->vtag_block[0].rport = rport;
|
||||
}
|
||||
}
|
||||
|
||||
@ -4549,8 +4640,8 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre
|
||||
if (inp->sctp_tcbhash) {
|
||||
LIST_REMOVE(stcb, sctp_tcbhash);
|
||||
}
|
||||
if (stcb->asoc.in_restart_hash) {
|
||||
LIST_REMOVE(stcb, sctp_tcbrestarhash);
|
||||
if (stcb->asoc.in_asocid_hash) {
|
||||
LIST_REMOVE(stcb, sctp_tcbasocidhash);
|
||||
}
|
||||
/* Now lets remove it from the list of ALL associations in the EP */
|
||||
LIST_REMOVE(stcb, sctp_tcblist);
|
||||
@ -4561,7 +4652,7 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre
|
||||
}
|
||||
/* pull from vtag hash */
|
||||
LIST_REMOVE(stcb, sctp_asocs);
|
||||
sctp_add_vtag_to_timewait(asoc->my_vtag, SCTP_TIME_WAIT);
|
||||
sctp_add_vtag_to_timewait(asoc->my_vtag, inp->sctp_lport, stcb->rport, SCTP_TIME_WAIT);
|
||||
|
||||
/*
|
||||
* Now restop the timers to be sure - this is paranoia at is finest!
|
||||
@ -4602,6 +4693,8 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre
|
||||
}
|
||||
sctp_free_remote_addr(sp->net);
|
||||
sctp_free_spbufspace(stcb, asoc, sp);
|
||||
if (sp->holds_key_ref)
|
||||
sctp_auth_key_release(stcb, sp->auth_keyid);
|
||||
/* Free the zone stuff */
|
||||
SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_strmoq), sp);
|
||||
SCTP_DECR_STRMOQ_COUNT();
|
||||
@ -4640,6 +4733,8 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre
|
||||
sctp_m_freem(chk->data);
|
||||
chk->data = NULL;
|
||||
}
|
||||
if (chk->holds_key_ref)
|
||||
sctp_auth_key_release(stcb, chk->auth_keyid);
|
||||
ccnt++;
|
||||
SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_chunk), chk);
|
||||
SCTP_DECR_CHK_COUNT();
|
||||
@ -4657,6 +4752,8 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre
|
||||
sctp_m_freem(chk->data);
|
||||
chk->data = NULL;
|
||||
}
|
||||
if (chk->holds_key_ref)
|
||||
sctp_auth_key_release(stcb, chk->auth_keyid);
|
||||
ccnt++;
|
||||
sctp_free_remote_addr(chk->whoTo);
|
||||
SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_chunk), chk);
|
||||
@ -4680,6 +4777,8 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre
|
||||
sctp_m_freem(chk->data);
|
||||
chk->data = NULL;
|
||||
}
|
||||
if (chk->holds_key_ref)
|
||||
sctp_auth_key_release(stcb, chk->auth_keyid);
|
||||
ccnt++;
|
||||
sctp_free_remote_addr(chk->whoTo);
|
||||
SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_chunk), chk);
|
||||
@ -4703,6 +4802,8 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre
|
||||
sctp_m_freem(chk->data);
|
||||
chk->data = NULL;
|
||||
}
|
||||
if (chk->holds_key_ref)
|
||||
sctp_auth_key_release(stcb, chk->auth_keyid);
|
||||
ccnt++;
|
||||
sctp_free_remote_addr(chk->whoTo);
|
||||
SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_chunk), chk);
|
||||
@ -4727,6 +4828,8 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre
|
||||
sctp_m_freem(chk->data);
|
||||
chk->data = NULL;
|
||||
}
|
||||
if (chk->holds_key_ref)
|
||||
sctp_auth_key_release(stcb, chk->auth_keyid);
|
||||
ccnt++;
|
||||
sctp_free_remote_addr(chk->whoTo);
|
||||
SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_chunk), chk);
|
||||
@ -4749,6 +4852,8 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre
|
||||
sctp_m_freem(chk->data);
|
||||
chk->data = NULL;
|
||||
}
|
||||
if (chk->holds_key_ref)
|
||||
sctp_auth_key_release(stcb, chk->auth_keyid);
|
||||
sctp_free_remote_addr(chk->whoTo);
|
||||
ccnt++;
|
||||
SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_chunk), chk);
|
||||
@ -5310,17 +5415,12 @@ sctp_pcb_init()
|
||||
&SCTP_BASE_INFO(hashtcpmark));
|
||||
SCTP_BASE_INFO(hashtblsize) = SCTP_BASE_SYSCTL(sctp_hashtblsize);
|
||||
|
||||
/* init the small hash table we use to track restarted asoc's */
|
||||
SCTP_BASE_INFO(sctp_restarthash) = SCTP_HASH_INIT(SCTP_STACK_VTAG_HASH_SIZE,
|
||||
&SCTP_BASE_INFO(hashrestartmark));
|
||||
|
||||
|
||||
SCTP_BASE_INFO(sctp_vrfhash) = SCTP_HASH_INIT(SCTP_SIZE_OF_VRF_HASH,
|
||||
&SCTP_BASE_INFO(hashvrfmark));
|
||||
|
||||
SCTP_BASE_INFO(vrf_ifn_hash) = SCTP_HASH_INIT(SCTP_VRF_IFN_HASH_SIZE,
|
||||
&SCTP_BASE_INFO(vrf_ifn_hashmark));
|
||||
|
||||
/* init the zones */
|
||||
/*
|
||||
* FIX ME: Should check for NULL returns, but if it does fail we are
|
||||
@ -5508,8 +5608,6 @@ sctp_pcb_finish(void)
|
||||
SCTP_HASH_FREE(SCTP_BASE_INFO(sctp_ephash), SCTP_BASE_INFO(hashmark));
|
||||
if (SCTP_BASE_INFO(sctp_tcpephash) != NULL)
|
||||
SCTP_HASH_FREE(SCTP_BASE_INFO(sctp_tcpephash), SCTP_BASE_INFO(hashtcpmark));
|
||||
if (SCTP_BASE_INFO(sctp_restarthash) != NULL)
|
||||
SCTP_HASH_FREE(SCTP_BASE_INFO(sctp_restarthash), SCTP_BASE_INFO(hashrestartmark));
|
||||
|
||||
}
|
||||
|
||||
@ -5900,6 +5998,8 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m,
|
||||
if (lsa) {
|
||||
(void)sctp_set_primary_addr(stcb, sa, NULL);
|
||||
}
|
||||
} else if (ptype == SCTP_HAS_NAT_SUPPORT) {
|
||||
stcb->asoc.peer_supports_nat = 1;
|
||||
} else if (ptype == SCTP_PRSCTP_SUPPORTED) {
|
||||
/* Peer supports pr-sctp */
|
||||
stcb->asoc.peer_supports_prsctp = 1;
|
||||
@ -6180,7 +6280,7 @@ sctp_set_primary_addr(struct sctp_tcb *stcb, struct sockaddr *sa,
|
||||
}
|
||||
|
||||
int
|
||||
sctp_is_vtag_good(struct sctp_inpcb *inp, uint32_t tag, struct timeval *now, int save_in_twait)
|
||||
sctp_is_vtag_good(struct sctp_inpcb *inp, uint32_t tag, uint16_t lport, uint16_t rport, struct timeval *now, int save_in_twait)
|
||||
{
|
||||
/*
|
||||
* This function serves two purposes. It will see if a TAG can be
|
||||
@ -6188,54 +6288,45 @@ sctp_is_vtag_good(struct sctp_inpcb *inp, uint32_t tag, struct timeval *now, int
|
||||
* tag. A secondary function it will do is purge out old tags that
|
||||
* can be removed.
|
||||
*/
|
||||
struct sctpasochead *head;
|
||||
struct sctpvtaghead *chain;
|
||||
struct sctp_tagblock *twait_block;
|
||||
struct sctpasochead *head;
|
||||
struct sctp_tcb *stcb;
|
||||
int i;
|
||||
|
||||
SCTP_INP_INFO_WLOCK();
|
||||
chain = &SCTP_BASE_INFO(vtag_timewait[(tag % SCTP_STACK_VTAG_HASH_SIZE))];
|
||||
/* First is the vtag in use ? */
|
||||
|
||||
SCTP_INP_INFO_RLOCK();
|
||||
head = &SCTP_BASE_INFO(sctp_asochash)[SCTP_PCBHASH_ASOC(tag,
|
||||
SCTP_BASE_INFO(hashasocmark))];
|
||||
if (head == NULL) {
|
||||
goto check_restart;
|
||||
/* invalid vtag */
|
||||
goto skip_vtag_check;
|
||||
}
|
||||
LIST_FOREACH(stcb, head, sctp_asocs) {
|
||||
|
||||
/*
|
||||
* We choose not to lock anything here. TCB's can't be
|
||||
* removed since we have the read lock, so they can't be
|
||||
* freed on us, same thing for the INP. I may be wrong with
|
||||
* this assumption, but we will go with it for now :-)
|
||||
*/
|
||||
if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) {
|
||||
continue;
|
||||
}
|
||||
if (stcb->asoc.my_vtag == tag) {
|
||||
/*
|
||||
* We should remove this if and return 0 always if
|
||||
* we want vtags unique across all endpoints. For
|
||||
* now within a endpoint is ok.
|
||||
*/
|
||||
if (inp == stcb->sctp_ep) {
|
||||
/* bad tag, in use */
|
||||
SCTP_INP_INFO_WUNLOCK();
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
}
|
||||
check_restart:
|
||||
/* Now lets check the restart hash */
|
||||
head = &SCTP_BASE_INFO(sctp_restarthash)[SCTP_PCBHASH_ASOC(tag,
|
||||
SCTP_BASE_INFO(hashrestartmark))];
|
||||
if (head == NULL) {
|
||||
goto check_time_wait;
|
||||
}
|
||||
LIST_FOREACH(stcb, head, sctp_tcbrestarhash) {
|
||||
if (stcb->asoc.assoc_id == tag) {
|
||||
/* candidate */
|
||||
if (inp == stcb->sctp_ep) {
|
||||
/* bad tag, in use */
|
||||
SCTP_INP_INFO_WUNLOCK();
|
||||
return (0);
|
||||
if (stcb->rport != rport) {
|
||||
continue;
|
||||
}
|
||||
if (stcb->sctp_ep->sctp_lport != lport) {
|
||||
continue;
|
||||
}
|
||||
/* Its a used tag set */
|
||||
SCTP_INP_INFO_WUNLOCK();
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
check_time_wait:
|
||||
skip_vtag_check:
|
||||
|
||||
chain = &SCTP_BASE_INFO(vtag_timewait[(tag % SCTP_STACK_VTAG_HASH_SIZE))];
|
||||
/* Now what about timed wait ? */
|
||||
if (!SCTP_LIST_EMPTY(chain)) {
|
||||
/*
|
||||
@ -6252,8 +6343,9 @@ sctp_is_vtag_good(struct sctp_inpcb *inp, uint32_t tag, struct timeval *now, int
|
||||
/* Audit expires this guy */
|
||||
twait_block->vtag_block[i].tv_sec_at_expire = 0;
|
||||
twait_block->vtag_block[i].v_tag = 0;
|
||||
} else if (twait_block->vtag_block[i].v_tag ==
|
||||
tag) {
|
||||
} else if ((twait_block->vtag_block[i].v_tag == tag) &&
|
||||
(twait_block->vtag_block[i].lport == lport) &&
|
||||
(twait_block->vtag_block[i].rport == rport)) {
|
||||
/* Bad tag, sorry :< */
|
||||
SCTP_INP_INFO_WUNLOCK();
|
||||
return (0);
|
||||
@ -6261,6 +6353,8 @@ sctp_is_vtag_good(struct sctp_inpcb *inp, uint32_t tag, struct timeval *now, int
|
||||
}
|
||||
}
|
||||
}
|
||||
SCTP_INP_INFO_RUNLOCK();
|
||||
#ifdef MICHAELS_EXPERIMENT
|
||||
/*-
|
||||
* Not found, ok to use the tag, add it to the time wait hash
|
||||
* as well this will prevent two sucessive cookies from getting
|
||||
@ -6269,9 +6363,12 @@ sctp_is_vtag_good(struct sctp_inpcb *inp, uint32_t tag, struct timeval *now, int
|
||||
* add this tag to the assoc hash we need to purge it from
|
||||
* the t-wait hash.
|
||||
*/
|
||||
SCTP_INP_INFO_WLOCK();
|
||||
if (save_in_twait)
|
||||
sctp_add_vtag_to_timewait(tag, TICKS_TO_SEC(inp->sctp_ep.def_cookie_life));
|
||||
sctp_add_vtag_to_timewait(tag, TICKS_TO_SEC(inp->sctp_ep.def_cookie_life, lport, rport));
|
||||
SCTP_INP_INFO_WUNLOCK();
|
||||
#endif
|
||||
|
||||
return (1);
|
||||
}
|
||||
|
||||
|
@ -133,6 +133,8 @@ struct sctp_block_entry {
|
||||
struct sctp_timewait {
|
||||
uint32_t tv_sec_at_expire; /* the seconds from boot to expire */
|
||||
uint32_t v_tag; /* the vtag that can not be reused */
|
||||
uint16_t lport; /* the local port used in vtag */
|
||||
uint16_t rport; /* the remote port used in vtag */
|
||||
};
|
||||
|
||||
struct sctp_tagblock {
|
||||
@ -148,8 +150,6 @@ struct sctp_epinfo {
|
||||
struct sctppcbhead *sctp_ephash;
|
||||
u_long hashmark;
|
||||
|
||||
struct sctpasochead *sctp_restarthash;
|
||||
u_long hashrestartmark;
|
||||
/*-
|
||||
* The TCP model represents a substantial overhead in that we get an
|
||||
* additional hash table to keep explicit connections in. The
|
||||
@ -411,6 +411,10 @@ struct sctp_inpcb {
|
||||
uint32_t total_recvs;
|
||||
uint32_t last_abort_code;
|
||||
uint32_t total_nospaces;
|
||||
struct sctpasochead *sctp_asocidhash;
|
||||
u_long hashasocidmark;
|
||||
uint32_t sctp_associd_counter;
|
||||
|
||||
#ifdef SCTP_ASOCLOG_OF_TSNS
|
||||
struct sctp_pcbtsn_rlog readlog[SCTP_READ_LOG_SIZE];
|
||||
uint32_t readlog_index;
|
||||
@ -424,7 +428,7 @@ struct sctp_tcb {
|
||||
* table */
|
||||
LIST_ENTRY(sctp_tcb) sctp_tcblist; /* list of all of the
|
||||
* TCB's */
|
||||
LIST_ENTRY(sctp_tcb) sctp_tcbrestarhash; /* next link in restart
|
||||
LIST_ENTRY(sctp_tcb) sctp_tcbasocidhash; /* next link in asocid
|
||||
* hash table */
|
||||
LIST_ENTRY(sctp_tcb) sctp_asocs; /* vtag hash list */
|
||||
struct sctp_block_entry *block_entry; /* pointer locked by socket
|
||||
@ -536,13 +540,16 @@ sctp_findassociation_ep_addr(struct sctp_inpcb **,
|
||||
struct sockaddr *, struct sctp_nets **, struct sockaddr *,
|
||||
struct sctp_tcb *);
|
||||
|
||||
struct sctp_tcb *
|
||||
sctp_findasoc_ep_asocid_locked(struct sctp_inpcb *inp, sctp_assoc_t asoc_id, int want_lock);
|
||||
|
||||
struct sctp_tcb *
|
||||
sctp_findassociation_ep_asocid(struct sctp_inpcb *,
|
||||
sctp_assoc_t, int);
|
||||
|
||||
struct sctp_tcb *
|
||||
sctp_findassociation_ep_asconf(struct mbuf *, int, int,
|
||||
struct sctphdr *, struct sctp_inpcb **, struct sctp_nets **);
|
||||
struct sctphdr *, struct sctp_inpcb **, struct sctp_nets **, uint32_t vrf_id);
|
||||
|
||||
int sctp_inpcb_alloc(struct socket *so, uint32_t vrf_id);
|
||||
|
||||
@ -557,12 +564,12 @@ sctp_aloc_assoc(struct sctp_inpcb *, struct sockaddr *,
|
||||
int sctp_free_assoc(struct sctp_inpcb *, struct sctp_tcb *, int, int);
|
||||
|
||||
|
||||
void sctp_delete_from_timewait(uint32_t);
|
||||
void sctp_delete_from_timewait(uint32_t, uint16_t, uint16_t);
|
||||
|
||||
int sctp_is_in_timewait(uint32_t tag);
|
||||
int sctp_is_in_timewait(uint32_t tag, uint16_t lport, uint16_t rport);
|
||||
|
||||
void
|
||||
sctp_add_vtag_to_timewait(uint32_t, uint32_t);
|
||||
sctp_add_vtag_to_timewait(uint32_t tag, uint32_t time, uint16_t lport, uint16_t rport);
|
||||
|
||||
void sctp_add_local_addr_ep(struct sctp_inpcb *, struct sctp_ifa *, uint32_t);
|
||||
|
||||
@ -593,7 +600,7 @@ int
|
||||
sctp_set_primary_addr(struct sctp_tcb *, struct sockaddr *,
|
||||
struct sctp_nets *);
|
||||
|
||||
int sctp_is_vtag_good(struct sctp_inpcb *, uint32_t, struct timeval *, int);
|
||||
int sctp_is_vtag_good(struct sctp_inpcb *, uint32_t, uint16_t lport, uint16_t rport, struct timeval *, int);
|
||||
|
||||
/* void sctp_drain(void); */
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*-
|
||||
* Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved.
|
||||
* Copyright (c) 2001-2008, by 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:
|
||||
@ -356,6 +356,8 @@ struct sctp_tmit_chunk {
|
||||
uint16_t send_size;
|
||||
uint16_t book_size;
|
||||
uint16_t mbcnt;
|
||||
uint16_t auth_keyid;
|
||||
uint8_t holds_key_ref; /* flag if auth keyid refcount is held */
|
||||
uint8_t pad_inplace;
|
||||
uint8_t do_rtt;
|
||||
uint8_t book_size_scale;
|
||||
@ -435,6 +437,8 @@ struct sctp_stream_queue_pending {
|
||||
uint16_t stream;
|
||||
uint16_t strseq;
|
||||
uint16_t act_flags;
|
||||
uint16_t auth_keyid;
|
||||
uint8_t holds_key_ref;
|
||||
uint8_t msg_is_complete;
|
||||
uint8_t some_taken;
|
||||
uint8_t addr_over;
|
||||
@ -472,6 +476,8 @@ struct sctp_asconf_addr {
|
||||
struct sctp_asconf_addr_param ap;
|
||||
struct sctp_ifa *ifa; /* save the ifa for add/del ip */
|
||||
uint8_t sent; /* has this been sent yet? */
|
||||
uint8_t special_del; /* not to be used in lookup */
|
||||
|
||||
};
|
||||
|
||||
struct sctp_scoping {
|
||||
@ -763,6 +769,12 @@ struct sctp_association {
|
||||
*/
|
||||
uint32_t highest_tsn_inside_map;
|
||||
|
||||
/* EY - new NR variables used for nr_sack based on mapping_array */
|
||||
uint8_t *nr_mapping_array;
|
||||
uint32_t nr_mapping_array_base_tsn;
|
||||
uint32_t highest_tsn_inside_nr_map;
|
||||
uint16_t nr_mapping_array_size;
|
||||
|
||||
uint32_t last_echo_tsn;
|
||||
uint32_t last_cwr_tsn;
|
||||
uint32_t fast_recovery_tsn;
|
||||
@ -992,6 +1004,8 @@ struct sctp_association {
|
||||
|
||||
/* flag to indicate if peer can do asconf */
|
||||
uint8_t peer_supports_asconf;
|
||||
/* EY - flag to indicate if peer can do nr_sack */
|
||||
uint8_t peer_supports_nr_sack;
|
||||
/* pr-sctp support flag */
|
||||
uint8_t peer_supports_prsctp;
|
||||
/* peer authentication support flag */
|
||||
@ -999,6 +1013,7 @@ struct sctp_association {
|
||||
/* stream resets are supported by the peer */
|
||||
uint8_t peer_supports_strreset;
|
||||
|
||||
uint8_t peer_supports_nat;
|
||||
/*
|
||||
* packet drop's are supported by the peer, we don't really care
|
||||
* about this but we bookkeep it anyway.
|
||||
@ -1028,7 +1043,9 @@ struct sctp_association {
|
||||
uint8_t delayed_connection;
|
||||
uint8_t ifp_had_enobuf;
|
||||
uint8_t saw_sack_with_frags;
|
||||
uint8_t in_restart_hash;
|
||||
/* EY */
|
||||
uint8_t saw_sack_with_nr_frags;
|
||||
uint8_t in_asocid_hash;
|
||||
uint8_t assoc_up_sent;
|
||||
uint8_t adaptation_needed;
|
||||
uint8_t adaptation_sent;
|
||||
@ -1037,6 +1054,8 @@ struct sctp_association {
|
||||
uint8_t sctp_cmt_on_off;
|
||||
uint8_t iam_blocking;
|
||||
uint8_t cookie_how[8];
|
||||
/* EY 05/05/08 - NR_SACK variable */
|
||||
uint8_t sctp_nr_sack_on_off;
|
||||
/* JRS 5/21/07 - CMT PF variable */
|
||||
uint8_t sctp_cmt_pf;
|
||||
/*
|
||||
|
@ -81,6 +81,8 @@ sctp_init_sysctls()
|
||||
SCTP_BASE_SYSCTL(sctp_add_more_threshold) = SCTPCTL_ADD_MORE_ON_OUTPUT_DEFAULT;
|
||||
SCTP_BASE_SYSCTL(sctp_nr_outgoing_streams_default) = SCTPCTL_OUTGOING_STREAMS_DEFAULT;
|
||||
SCTP_BASE_SYSCTL(sctp_cmt_on_off) = SCTPCTL_CMT_ON_OFF_DEFAULT;
|
||||
/* EY */
|
||||
SCTP_BASE_SYSCTL(sctp_nr_sack_on_off) = SCTPCTL_NR_SACK_ON_OFF_DEFAULT;
|
||||
SCTP_BASE_SYSCTL(sctp_cmt_use_dac) = SCTPCTL_CMT_USE_DAC_DEFAULT;
|
||||
SCTP_BASE_SYSCTL(sctp_cmt_pf) = SCTPCTL_CMT_PF_DEFAULT;
|
||||
SCTP_BASE_SYSCTL(sctp_use_cwnd_based_maxburst) = SCTPCTL_CWND_MAXBURST_DEFAULT;
|
||||
@ -109,6 +111,7 @@ sctp_init_sysctls()
|
||||
SCTP_BASE_SYSCTL(sctp_udp_tunneling_for_client_enable) = SCTPCTL_UDP_TUNNELING_FOR_CLIENT_ENABLE_DEFAULT;
|
||||
SCTP_BASE_SYSCTL(sctp_udp_tunneling_port) = SCTPCTL_UDP_TUNNELING_PORT_DEFAULT;
|
||||
SCTP_BASE_SYSCTL(sctp_enable_sack_immediately) = SCTPCTL_SACK_IMMEDIATELY_ENABLE_DEFAULT;
|
||||
SCTP_BASE_SYSCTL(sctp_inits_include_nat_friendly) = SCTPCTL_NAT_FRIENDLY_DEFAULT;
|
||||
#if defined(SCTP_DEBUG)
|
||||
SCTP_BASE_SYSCTL(sctp_debug_on) = SCTPCTL_DEBUG_DEFAULT;
|
||||
#endif
|
||||
@ -574,6 +577,8 @@ sysctl_sctp_check(SYSCTL_HANDLER_ARGS)
|
||||
RANGECHK(SCTP_BASE_SYSCTL(sctp_add_more_threshold), SCTPCTL_ADD_MORE_ON_OUTPUT_MIN, SCTPCTL_ADD_MORE_ON_OUTPUT_MAX);
|
||||
RANGECHK(SCTP_BASE_SYSCTL(sctp_nr_outgoing_streams_default), SCTPCTL_OUTGOING_STREAMS_MIN, SCTPCTL_OUTGOING_STREAMS_MAX);
|
||||
RANGECHK(SCTP_BASE_SYSCTL(sctp_cmt_on_off), SCTPCTL_CMT_ON_OFF_MIN, SCTPCTL_CMT_ON_OFF_MAX);
|
||||
/* EY */
|
||||
RANGECHK(SCTP_BASE_SYSCTL(sctp_nr_sack_on_off), SCTPCTL_NR_SACK_ON_OFF_MIN, SCTPCTL_NR_SACK_ON_OFF_MAX);
|
||||
RANGECHK(SCTP_BASE_SYSCTL(sctp_cmt_use_dac), SCTPCTL_CMT_USE_DAC_MIN, SCTPCTL_CMT_USE_DAC_MAX);
|
||||
RANGECHK(SCTP_BASE_SYSCTL(sctp_cmt_pf), SCTPCTL_CMT_PF_MIN, SCTPCTL_CMT_PF_MAX);
|
||||
RANGECHK(SCTP_BASE_SYSCTL(sctp_use_cwnd_based_maxburst), SCTPCTL_CWND_MAXBURST_MIN, SCTPCTL_CWND_MAXBURST_MAX);
|
||||
@ -601,6 +606,8 @@ sysctl_sctp_check(SYSCTL_HANDLER_ARGS)
|
||||
#endif
|
||||
RANGECHK(SCTP_BASE_SYSCTL(sctp_udp_tunneling_for_client_enable), SCTPCTL_UDP_TUNNELING_FOR_CLIENT_ENABLE_MIN, SCTPCTL_UDP_TUNNELING_FOR_CLIENT_ENABLE_MAX);
|
||||
RANGECHK(SCTP_BASE_SYSCTL(sctp_enable_sack_immediately), SCTPCTL_SACK_IMMEDIATELY_ENABLE_MIN, SCTPCTL_SACK_IMMEDIATELY_ENABLE_MAX);
|
||||
RANGECHK(SCTP_BASE_SYSCTL(sctp_inits_include_nat_friendly), SCTPCTL_NAT_FRIENDLY_MIN, SCTPCTL_NAT_FRIENDLY_MAX);
|
||||
|
||||
#ifdef SCTP_DEBUG
|
||||
RANGECHK(SCTP_BASE_SYSCTL(sctp_debug_on), SCTPCTL_DEBUG_MIN, SCTPCTL_DEBUG_MAX);
|
||||
#endif
|
||||
@ -767,6 +774,11 @@ SYSCTL_PROC(_net_inet_sctp, OID_AUTO, cmt_on_off, CTLTYPE_INT | CTLFLAG_RW,
|
||||
&SCTP_BASE_SYSCTL(sctp_cmt_on_off), 0, sysctl_sctp_check, "IU",
|
||||
SCTPCTL_CMT_ON_OFF_DESC);
|
||||
|
||||
/* EY */
|
||||
SYSCTL_PROC(_net_inet_sctp, OID_AUTO, nr_sack_on_off, CTLTYPE_INT | CTLFLAG_RW,
|
||||
&SCTP_BASE_SYSCTL(sctp_nr_sack_on_off), 0, sysctl_sctp_check, "IU",
|
||||
SCTPCTL_NR_SACK_ON_OFF_DESC);
|
||||
|
||||
SYSCTL_PROC(_net_inet_sctp, OID_AUTO, cmt_use_dac, CTLTYPE_INT | CTLFLAG_RW,
|
||||
&SCTP_BASE_SYSCTL(sctp_cmt_use_dac), 0, sysctl_sctp_check, "IU",
|
||||
SCTPCTL_CMT_USE_DAC_DESC);
|
||||
@ -880,6 +892,10 @@ SYSCTL_PROC(_net_inet_sctp, OID_AUTO, enable_sack_immediately, CTLTYPE_INT | CTL
|
||||
&SCTP_BASE_SYSCTL(sctp_enable_sack_immediately), 0, sysctl_sctp_check, "IU",
|
||||
SCTPCTL_SACK_IMMEDIATELY_ENABLE_DESC);
|
||||
|
||||
SYSCTL_PROC(_net_inet_sctp, OID_AUTO, nat_friendly_init, CTLTYPE_INT | CTLFLAG_RW,
|
||||
&SCTP_BASE_SYSCTL(sctp_inits_include_nat_friendly), 0, sysctl_sctp_check, "IU",
|
||||
SCTPCTL_NAT_FRIENDLY_DESC);
|
||||
|
||||
#ifdef SCTP_DEBUG
|
||||
SYSCTL_PROC(_net_inet_sctp, OID_AUTO, debug, CTLTYPE_INT | CTLFLAG_RW,
|
||||
&SCTP_BASE_SYSCTL(sctp_debug_on), 0, sysctl_sctp_check, "IU",
|
||||
|
@ -74,6 +74,8 @@ struct sctp_sysctl {
|
||||
uint32_t sctp_nr_outgoing_streams_default;
|
||||
uint32_t sctp_cmt_on_off;
|
||||
uint32_t sctp_cmt_use_dac;
|
||||
/* EY 5/5/08 - nr_sack flag variable */
|
||||
uint32_t sctp_nr_sack_on_off;
|
||||
uint32_t sctp_cmt_pf;
|
||||
uint32_t sctp_use_cwnd_based_maxburst;
|
||||
uint32_t sctp_early_fr;
|
||||
@ -95,6 +97,7 @@ struct sctp_sysctl {
|
||||
uint32_t sctp_default_frag_interleave;
|
||||
uint32_t sctp_mobility_base;
|
||||
uint32_t sctp_mobility_fasthandoff;
|
||||
uint32_t sctp_inits_include_nat_friendly;
|
||||
#if defined(SCTP_LOCAL_TRACE_BUF)
|
||||
struct sctp_log sctp_log;
|
||||
#endif
|
||||
@ -322,6 +325,12 @@ struct sctp_sysctl {
|
||||
#define SCTPCTL_CMT_ON_OFF_MAX 1
|
||||
#define SCTPCTL_CMT_ON_OFF_DEFAULT 0
|
||||
|
||||
/* EY - nr_sack_on_off: NR_SACK on/off flag */
|
||||
#define SCTPCTL_NR_SACK_ON_OFF_DESC "NR_SACK on/off flag"
|
||||
#define SCTPCTL_NR_SACK_ON_OFF_MIN 0
|
||||
#define SCTPCTL_NR_SACK_ON_OFF_MAX 1
|
||||
#define SCTPCTL_NR_SACK_ON_OFF_DEFAULT 0
|
||||
|
||||
/* cmt_use_dac: CMT DAC on/off flag */
|
||||
#define SCTPCTL_CMT_USE_DAC_DESC "CMT DAC on/off flag"
|
||||
#define SCTPCTL_CMT_USE_DAC_MIN 0
|
||||
@ -466,6 +475,13 @@ struct sctp_sysctl {
|
||||
#define SCTPCTL_SACK_IMMEDIATELY_ENABLE_MAX 1
|
||||
#define SCTPCTL_SACK_IMMEDIATELY_ENABLE_DEFAULT SCTPCTL_SACK_IMMEDIATELY_ENABLE_MIN
|
||||
|
||||
/* Enable sending of the SACK-IMMEDIATELY bit */
|
||||
#define SCTPCTL_NAT_FRIENDLY_INITS "Enable sending of the nat-friendly SCTP option on INITs."
|
||||
#define SCTPCTL_NAT_FRIENDLY_INITS_MIN 0
|
||||
#define SCTPCTL_NAT_FRIENDLY_INITS_MAX 1
|
||||
#define SCTPCTL_NAT_FRIENDLY_INITS_DEFAULT SCTPCTL_NAT_FRIENDLY_INITS_MIN
|
||||
|
||||
|
||||
#if defined(SCTP_DEBUG)
|
||||
/* debug: Configure debug output */
|
||||
#define SCTPCTL_DEBUG_DESC "Configure debug output"
|
||||
|
@ -49,7 +49,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <netinet/sctp_input.h>
|
||||
#include <netinet/sctp.h>
|
||||
#include <netinet/sctp_uio.h>
|
||||
|
||||
#include <netinet/udp.h>
|
||||
|
||||
|
||||
void
|
||||
@ -769,8 +769,8 @@ sctp_mark_all_for_resend(struct sctp_tcb *stcb,
|
||||
(SCTP_RESPONSE_TO_USER_REQ | SCTP_NOTIFY_DATAGRAM_SENT),
|
||||
&stcb->asoc.sent_queue, SCTP_SO_NOT_LOCKED);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (PR_SCTP_RTX_ENABLED(chk->flags)) {
|
||||
/* Has it been retransmitted tv_sec times? */
|
||||
@ -781,8 +781,8 @@ sctp_mark_all_for_resend(struct sctp_tcb *stcb,
|
||||
(SCTP_RESPONSE_TO_USER_REQ | SCTP_NOTIFY_DATAGRAM_SENT),
|
||||
&stcb->asoc.sent_queue, SCTP_SO_NOT_LOCKED);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (chk->sent < SCTP_DATAGRAM_RESEND) {
|
||||
sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt);
|
||||
@ -1088,7 +1088,11 @@ sctp_t3rxt_timer(struct sctp_inpcb *inp,
|
||||
* more, request a RTT update
|
||||
*/
|
||||
if (sctp_send_hb(stcb, 1, net) < 0)
|
||||
return 1;
|
||||
/*
|
||||
* Less than 0 means we lost
|
||||
* the assoc
|
||||
*/
|
||||
return (1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1146,7 +1150,8 @@ sctp_t3rxt_timer(struct sctp_inpcb *inp,
|
||||
* manually.
|
||||
*/
|
||||
if (sctp_send_hb(stcb, 1, net) < 0)
|
||||
return 1;
|
||||
/* Return less than 0 means we lost the association */
|
||||
return (1);
|
||||
}
|
||||
/*
|
||||
* Special case for cookie-echo'ed case, we don't do output but must
|
||||
@ -1789,6 +1794,9 @@ sctp_pathmtu_timer(struct sctp_inpcb *inp,
|
||||
}
|
||||
if (net->ro._s_addr) {
|
||||
mtu = SCTP_GATHER_MTU_FROM_ROUTE(net->ro._s_addr, &net->ro._s_addr.sa, net->ro.ro_rt);
|
||||
if (net->port) {
|
||||
mtu -= sizeof(struct udphdr);
|
||||
}
|
||||
if (mtu > next_mtu) {
|
||||
net->mtu = next_mtu;
|
||||
}
|
||||
|
@ -56,6 +56,7 @@ struct sctp_event_subscribe {
|
||||
uint8_t sctp_partial_delivery_event;
|
||||
uint8_t sctp_adaptation_layer_event;
|
||||
uint8_t sctp_authentication_event;
|
||||
uint8_t sctp_sender_dry_event;
|
||||
uint8_t sctp_stream_reset_events;
|
||||
};
|
||||
|
||||
@ -139,17 +140,18 @@ struct sctp_snd_all_completes {
|
||||
};
|
||||
|
||||
/* Flags that go into the sinfo->sinfo_flags field */
|
||||
#define SCTP_EOF 0x0100/* Start shutdown procedures */
|
||||
#define SCTP_ABORT 0x0200/* Send an ABORT to peer */
|
||||
#define SCTP_UNORDERED 0x0400/* Message is un-ordered */
|
||||
#define SCTP_ADDR_OVER 0x0800/* Override the primary-address */
|
||||
#define SCTP_SENDALL 0x1000/* Send this on all associations */
|
||||
#define SCTP_EOR 0x2000/* end of message signal */
|
||||
#define SCTP_PR_POLICY_VALID 0x4000 /* pr sctp policy valid */
|
||||
#define SCTP_EOF 0x0100 /* Start shutdown procedures */
|
||||
#define SCTP_ABORT 0x0200 /* Send an ABORT to peer */
|
||||
#define SCTP_UNORDERED 0x0400 /* Message is un-ordered */
|
||||
#define SCTP_ADDR_OVER 0x0800 /* Override the primary-address */
|
||||
#define SCTP_SENDALL 0x1000 /* Send this on all associations */
|
||||
#define SCTP_EOR 0x2000 /* end of message signal */
|
||||
#define SCTP_SACK_IMMEDIATELY 0x4000 /* Set I-Bit */
|
||||
|
||||
#define INVALID_SINFO_FLAG(x) (((x) & 0xffffff00 \
|
||||
& ~(SCTP_EOF | SCTP_ABORT | SCTP_UNORDERED |\
|
||||
SCTP_ADDR_OVER | SCTP_SENDALL | SCTP_EOR)) != 0)
|
||||
SCTP_ADDR_OVER | SCTP_SENDALL | SCTP_EOR |\
|
||||
SCTP_SACK_IMMEDIATELY)) != 0)
|
||||
/* for the endpoint */
|
||||
|
||||
/* The lower byte is an enumeration of PR-SCTP policies */
|
||||
@ -346,6 +348,16 @@ struct sctp_authkey_event {
|
||||
|
||||
/* indication values */
|
||||
#define SCTP_AUTH_NEWKEY 0x0001
|
||||
#define SCTP_AUTH_NO_AUTH 0x0002
|
||||
#define SCTP_AUTH_FREE_KEY 0x0003
|
||||
|
||||
|
||||
struct sctp_sender_dry_event {
|
||||
uint16_t sender_dry_type;
|
||||
uint16_t sender_dry_flags;
|
||||
uint32_t sender_dry_length;
|
||||
sctp_assoc_t sender_dry_assoc_id;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
@ -386,6 +398,7 @@ union sctp_notification {
|
||||
struct sctp_adaption_event sn_adaption_event;
|
||||
struct sctp_pdapi_event sn_pdapi_event;
|
||||
struct sctp_authkey_event sn_auth_event;
|
||||
struct sctp_sender_dry_event sn_sender_dry_event;
|
||||
struct sctp_stream_reset_event sn_strreset_event;
|
||||
};
|
||||
|
||||
@ -401,7 +414,7 @@ union sctp_notification {
|
||||
#define SCTP_PARTIAL_DELIVERY_EVENT 0x0007
|
||||
#define SCTP_AUTHENTICATION_EVENT 0x0008
|
||||
#define SCTP_STREAM_RESET_EVENT 0x0009
|
||||
|
||||
#define SCTP_SENDER_DRY_EVENT 0x000a
|
||||
|
||||
/*
|
||||
* socket option structs
|
||||
@ -539,6 +552,7 @@ struct sctp_assoc_value {
|
||||
};
|
||||
|
||||
struct sctp_assoc_ids {
|
||||
uint32_t gaids_number_of_ids;
|
||||
sctp_assoc_t gaids_assoc_id[0];
|
||||
};
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*-
|
||||
* Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved.
|
||||
* Copyright (c) 2001-2008, by 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:
|
||||
@ -49,6 +49,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <netinet/sctp_auth.h>
|
||||
#include <netinet/sctp_bsd_addr.h>
|
||||
#include <netinet/sctp_cc_functions.h>
|
||||
#include <netinet/udp.h>
|
||||
|
||||
|
||||
|
||||
@ -201,6 +202,9 @@ sctp_notify_mbuf(struct sctp_inpcb *inp,
|
||||
/* Adjust destination size limit */
|
||||
if (net->mtu > nxtsz) {
|
||||
net->mtu = nxtsz;
|
||||
if (net->port) {
|
||||
net->mtu -= sizeof(struct udphdr);
|
||||
}
|
||||
}
|
||||
/* now what about the ep? */
|
||||
if (stcb->asoc.smallest_mtu > nxtsz) {
|
||||
@ -507,8 +511,10 @@ sctp_attach(struct socket *so, int proto, struct thread *p)
|
||||
struct inpcb *ip_inp;
|
||||
int error;
|
||||
uint32_t vrf_id = SCTP_DEFAULT_VRFID;
|
||||
|
||||
#ifdef IPSEC
|
||||
uint32_t flags;
|
||||
|
||||
#endif
|
||||
|
||||
inp = (struct sctp_inpcb *)so->so_pcb;
|
||||
@ -1704,6 +1710,29 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
|
||||
*optsize = sizeof(*av);
|
||||
}
|
||||
break;
|
||||
/* EY - set socket option for nr_sacks */
|
||||
case SCTP_NR_SACK_ON_OFF:
|
||||
{
|
||||
struct sctp_assoc_value *av;
|
||||
|
||||
SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
|
||||
if (SCTP_BASE_SYSCTL(sctp_nr_sack_on_off)) {
|
||||
SCTP_FIND_STCB(inp, stcb, av->assoc_id);
|
||||
if (stcb) {
|
||||
av->assoc_value = stcb->asoc.sctp_nr_sack_on_off;
|
||||
SCTP_TCB_UNLOCK(stcb);
|
||||
|
||||
} else {
|
||||
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN);
|
||||
error = ENOTCONN;
|
||||
}
|
||||
} else {
|
||||
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT);
|
||||
error = ENOPROTOOPT;
|
||||
}
|
||||
*optsize = sizeof(*av);
|
||||
}
|
||||
break;
|
||||
/* JRS - Get socket option for pluggable congestion control */
|
||||
case SCTP_PLUGGABLE_CC:
|
||||
{
|
||||
@ -1767,7 +1796,7 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
|
||||
|
||||
SCTP_CHECK_AND_CAST(ids, optval, struct sctp_assoc_ids, *optsize);
|
||||
at = 0;
|
||||
limit = *optsize / sizeof(sctp_assoc_t);
|
||||
limit = (*optsize - sizeof(uint32_t)) / sizeof(sctp_assoc_t);
|
||||
SCTP_INP_RLOCK(inp);
|
||||
LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
|
||||
if (at < limit) {
|
||||
@ -1779,7 +1808,8 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
|
||||
}
|
||||
}
|
||||
SCTP_INP_RUNLOCK(inp);
|
||||
*optsize = at * sizeof(sctp_assoc_t);
|
||||
ids->gaids_number_of_ids = at;
|
||||
*optsize = ((at * sizeof(sctp_assoc_t)) + sizeof(uint32_t));
|
||||
}
|
||||
break;
|
||||
case SCTP_CONTEXT:
|
||||
@ -1961,6 +1991,9 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
|
||||
if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_AUTHEVNT))
|
||||
events->sctp_authentication_event = 1;
|
||||
|
||||
if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_DRYEVNT))
|
||||
events->sctp_sender_dry_event = 1;
|
||||
|
||||
if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_STREAM_RESETEVNT))
|
||||
events->sctp_stream_reset_events = 1;
|
||||
SCTP_INP_RUNLOCK(inp);
|
||||
@ -2532,7 +2565,7 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
|
||||
|
||||
if (stcb) {
|
||||
/* get the active key on the assoc */
|
||||
scact->scact_keynumber = stcb->asoc.authinfo.assoc_keyid;
|
||||
scact->scact_keynumber = stcb->asoc.authinfo.active_keyid;
|
||||
SCTP_TCB_UNLOCK(stcb);
|
||||
} else {
|
||||
/* get the endpoint active key */
|
||||
@ -2789,6 +2822,27 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
|
||||
}
|
||||
}
|
||||
break;
|
||||
/* EY nr_sack_on_off socket option */
|
||||
case SCTP_NR_SACK_ON_OFF:
|
||||
{
|
||||
struct sctp_assoc_value *av;
|
||||
|
||||
SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
|
||||
if (SCTP_BASE_SYSCTL(sctp_nr_sack_on_off)) {
|
||||
SCTP_FIND_STCB(inp, stcb, av->assoc_id);
|
||||
if (stcb) {
|
||||
stcb->asoc.sctp_nr_sack_on_off = (uint8_t) av->assoc_value;
|
||||
SCTP_TCB_UNLOCK(stcb);
|
||||
} else {
|
||||
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN);
|
||||
error = ENOTCONN;
|
||||
}
|
||||
} else {
|
||||
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT);
|
||||
error = ENOPROTOOPT;
|
||||
}
|
||||
}
|
||||
break;
|
||||
/* JRS - Set socket option for pluggable congestion control */
|
||||
case SCTP_PLUGGABLE_CC:
|
||||
{
|
||||
@ -3012,7 +3066,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
|
||||
}
|
||||
shared_key->key = key;
|
||||
shared_key->keyid = sca->sca_keynumber;
|
||||
sctp_insert_sharedkey(shared_keys, shared_key);
|
||||
error = sctp_insert_sharedkey(shared_keys, shared_key);
|
||||
SCTP_TCB_UNLOCK(stcb);
|
||||
} else {
|
||||
/* set it on the endpoint */
|
||||
@ -3046,7 +3100,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
|
||||
}
|
||||
shared_key->key = key;
|
||||
shared_key->keyid = sca->sca_keynumber;
|
||||
sctp_insert_sharedkey(shared_keys, shared_key);
|
||||
error = sctp_insert_sharedkey(shared_keys, shared_key);
|
||||
SCTP_INP_WUNLOCK(inp);
|
||||
}
|
||||
break;
|
||||
@ -3108,22 +3162,29 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
|
||||
{
|
||||
struct sctp_authkeyid *scact;
|
||||
|
||||
SCTP_CHECK_AND_CAST(scact, optval, struct sctp_authkeyid, optsize);
|
||||
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) {
|
||||
/* set the active key on the assoc */
|
||||
if (sctp_auth_setactivekey(stcb, scact->scact_keynumber)) {
|
||||
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
|
||||
if (sctp_auth_setactivekey(stcb,
|
||||
scact->scact_keynumber)) {
|
||||
SCTP_LTRACE_ERR_RET(inp, NULL, NULL,
|
||||
SCTP_FROM_SCTP_USRREQ,
|
||||
EINVAL);
|
||||
error = EINVAL;
|
||||
}
|
||||
SCTP_TCB_UNLOCK(stcb);
|
||||
} else {
|
||||
/* set the active key on the endpoint */
|
||||
SCTP_INP_WLOCK(inp);
|
||||
if (sctp_auth_setactivekey_ep(inp, scact->scact_keynumber)) {
|
||||
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
|
||||
if (sctp_auth_setactivekey_ep(inp,
|
||||
scact->scact_keynumber)) {
|
||||
SCTP_LTRACE_ERR_RET(inp, NULL, NULL,
|
||||
SCTP_FROM_SCTP_USRREQ,
|
||||
EINVAL);
|
||||
error = EINVAL;
|
||||
}
|
||||
SCTP_INP_WUNLOCK(inp);
|
||||
@ -3134,20 +3195,58 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
|
||||
{
|
||||
struct sctp_authkeyid *scdel;
|
||||
|
||||
SCTP_CHECK_AND_CAST(scdel, optval, struct sctp_authkeyid, optsize);
|
||||
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) {
|
||||
if (sctp_delete_sharedkey(stcb, scdel->scact_keynumber)) {
|
||||
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
|
||||
if (sctp_delete_sharedkey(stcb,
|
||||
scdel->scact_keynumber)) {
|
||||
SCTP_LTRACE_ERR_RET(inp, NULL, NULL,
|
||||
SCTP_FROM_SCTP_USRREQ,
|
||||
EINVAL);
|
||||
error = EINVAL;
|
||||
}
|
||||
SCTP_TCB_UNLOCK(stcb);
|
||||
} else {
|
||||
SCTP_INP_WLOCK(inp);
|
||||
if (sctp_delete_sharedkey_ep(inp, scdel->scact_keynumber)) {
|
||||
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
|
||||
if (sctp_delete_sharedkey_ep(inp,
|
||||
scdel->scact_keynumber)) {
|
||||
SCTP_LTRACE_ERR_RET(inp, NULL, NULL,
|
||||
SCTP_FROM_SCTP_USRREQ,
|
||||
EINVAL);
|
||||
error = EINVAL;
|
||||
}
|
||||
SCTP_INP_WUNLOCK(inp);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SCTP_AUTH_DEACTIVATE_KEY:
|
||||
{
|
||||
struct sctp_authkeyid *keyid;
|
||||
|
||||
SCTP_CHECK_AND_CAST(keyid, optval, struct sctp_authkeyid,
|
||||
optsize);
|
||||
SCTP_FIND_STCB(inp, stcb, keyid->scact_assoc_id);
|
||||
|
||||
/* deactivate the key from the right place */
|
||||
if (stcb) {
|
||||
if (sctp_deact_sharedkey(stcb,
|
||||
keyid->scact_keynumber)) {
|
||||
SCTP_LTRACE_ERR_RET(inp, NULL, NULL,
|
||||
SCTP_FROM_SCTP_USRREQ,
|
||||
EINVAL);
|
||||
error = EINVAL;
|
||||
}
|
||||
SCTP_TCB_UNLOCK(stcb);
|
||||
} else {
|
||||
SCTP_INP_WLOCK(inp);
|
||||
if (sctp_deact_sharedkey_ep(inp,
|
||||
keyid->scact_keynumber)) {
|
||||
SCTP_LTRACE_ERR_RET(inp, NULL, NULL,
|
||||
SCTP_FROM_SCTP_USRREQ,
|
||||
EINVAL);
|
||||
error = EINVAL;
|
||||
}
|
||||
SCTP_INP_WUNLOCK(inp);
|
||||
@ -3414,6 +3513,12 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
|
||||
sctp_feature_off(inp, SCTP_PCB_FLAGS_AUTHEVNT);
|
||||
}
|
||||
|
||||
if (events->sctp_sender_dry_event) {
|
||||
sctp_feature_on(inp, SCTP_PCB_FLAGS_DRYEVNT);
|
||||
} else {
|
||||
sctp_feature_off(inp, SCTP_PCB_FLAGS_DRYEVNT);
|
||||
}
|
||||
|
||||
if (events->sctp_stream_reset_events) {
|
||||
sctp_feature_on(inp, SCTP_PCB_FLAGS_STREAM_RESETEVNT);
|
||||
} else {
|
||||
@ -4123,6 +4228,7 @@ sctp_connect(struct socket *so, struct sockaddr *addr, struct thread *p)
|
||||
#ifdef INET6
|
||||
if (addr->sa_family == AF_INET6) {
|
||||
struct sockaddr_in6 *sin6p;
|
||||
|
||||
if (addr->sa_len != sizeof(struct sockaddr_in6)) {
|
||||
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
|
||||
return (EINVAL);
|
||||
@ -4136,6 +4242,7 @@ sctp_connect(struct socket *so, struct sockaddr *addr, struct thread *p)
|
||||
#endif
|
||||
if (addr->sa_family == AF_INET) {
|
||||
struct sockaddr_in *sinp;
|
||||
|
||||
if (addr->sa_len != sizeof(struct sockaddr_in)) {
|
||||
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
|
||||
return (EINVAL);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*-
|
||||
* Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved.
|
||||
* Copyright (c) 2001-2008, by 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:
|
||||
@ -86,6 +86,10 @@ extern struct pr_usrreqs sctp_usrreqs;
|
||||
}
|
||||
|
||||
#define sctp_free_a_strmoq(_stcb, _strmoq) { \
|
||||
if ((_strmoq)->holds_key_ref) { \
|
||||
sctp_auth_key_release(stcb, sp->auth_keyid); \
|
||||
(_strmoq)->holds_key_ref = 0; \
|
||||
} \
|
||||
SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_strmoq), (_strmoq)); \
|
||||
SCTP_DECR_STRMOQ_COUNT(); \
|
||||
}
|
||||
@ -94,11 +98,15 @@ extern struct pr_usrreqs sctp_usrreqs;
|
||||
(_strmoq) = SCTP_ZONE_GET(SCTP_BASE_INFO(ipi_zone_strmoq), struct sctp_stream_queue_pending); \
|
||||
if ((_strmoq)) { \
|
||||
SCTP_INCR_STRMOQ_COUNT(); \
|
||||
(_strmoq)->holds_key_ref = 0; \
|
||||
} \
|
||||
}
|
||||
|
||||
|
||||
#define sctp_free_a_chunk(_stcb, _chk) { \
|
||||
if ((_chk)->holds_key_ref) {\
|
||||
sctp_auth_key_release((_stcb), (_chk)->auth_keyid); \
|
||||
(_chk)->holds_key_ref = 0; \
|
||||
} \
|
||||
if(_stcb) { \
|
||||
SCTP_TCB_LOCK_ASSERT((_stcb)); \
|
||||
if ((_chk)->whoTo) { \
|
||||
@ -126,21 +134,22 @@ extern struct pr_usrreqs sctp_usrreqs;
|
||||
if ((_chk)) { \
|
||||
SCTP_INCR_CHK_COUNT(); \
|
||||
(_chk)->whoTo = NULL; \
|
||||
(_chk)->holds_key_ref = 0; \
|
||||
} \
|
||||
} else { \
|
||||
(_chk) = TAILQ_FIRST(&(_stcb)->asoc.free_chunks); \
|
||||
TAILQ_REMOVE(&(_stcb)->asoc.free_chunks, (_chk), sctp_next); \
|
||||
atomic_subtract_int(&SCTP_BASE_INFO(ipi_free_chunks), 1); \
|
||||
(_chk)->holds_key_ref = 0; \
|
||||
SCTP_STAT_INCR(sctps_cached_chk); \
|
||||
(_stcb)->asoc.free_chunk_cnt--; \
|
||||
} \
|
||||
}
|
||||
|
||||
|
||||
|
||||
#define sctp_free_remote_addr(__net) { \
|
||||
if ((__net)) { \
|
||||
if (atomic_fetchadd_int(&(__net)->ref_count, -1) == 1) { \
|
||||
if (SCTP_DECREMENT_AND_CHECK_REFCOUNT(&(__net)->ref_count)) { \
|
||||
(void)SCTP_OS_TIMER_STOP(&(__net)->rxt_timer.timer); \
|
||||
(void)SCTP_OS_TIMER_STOP(&(__net)->pmtu_timer.timer); \
|
||||
(void)SCTP_OS_TIMER_STOP(&(__net)->fr_timer.timer); \
|
||||
@ -160,64 +169,18 @@ extern struct pr_usrreqs sctp_usrreqs;
|
||||
} \
|
||||
}
|
||||
|
||||
#ifdef INVARIANTS
|
||||
|
||||
|
||||
#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"); \
|
||||
} \
|
||||
SCTP_SAVE_ATOMIC_DECREMENT(&(sb)->sb_cc, SCTP_BUF_LEN((m))); \
|
||||
SCTP_SAVE_ATOMIC_DECREMENT(&(sb)->sb_mbcnt, MSIZE); \
|
||||
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.my_rwnd_control_len,-(MSIZE)); \
|
||||
if (val < MSIZE) { \
|
||||
panic("asoc->mbcnt goes negative"); \
|
||||
} \
|
||||
SCTP_SAVE_ATOMIC_DECREMENT(&(stcb)->asoc.sb_cc, SCTP_BUF_LEN((m))); \
|
||||
SCTP_SAVE_ATOMIC_DECREMENT(&(stcb)->asoc.my_rwnd_control_len, MSIZE); \
|
||||
} \
|
||||
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))); \
|
||||
}
|
||||
|
||||
|
||||
#else
|
||||
|
||||
#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))) { \
|
||||
(sb)->sb_cc = 0;\
|
||||
} \
|
||||
val = atomic_fetchadd_int(&(sb)->sb_mbcnt,-(MSIZE)); \
|
||||
if (val < MSIZE) { \
|
||||
(sb)->sb_mbcnt = 0; \
|
||||
} \
|
||||
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))) {\
|
||||
(stcb)->asoc.sb_cc = 0; \
|
||||
} \
|
||||
val = atomic_fetchadd_int(&(stcb)->asoc.my_rwnd_control_len,-(MSIZE)); \
|
||||
if (val < MSIZE) { \
|
||||
(stcb)->asoc.my_rwnd_control_len = 0; \
|
||||
} \
|
||||
} \
|
||||
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))); \
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#define sctp_sballoc(stcb, sb, m) { \
|
||||
atomic_add_int(&(sb)->sb_cc,SCTP_BUF_LEN((m))); \
|
||||
atomic_add_int(&(sb)->sb_mbcnt, MSIZE); \
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*-
|
||||
* Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved.
|
||||
* Copyright (c) 2001-2008, by 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:
|
||||
@ -848,7 +848,7 @@ sctp_select_initial_TSN(struct sctp_pcb *inp)
|
||||
}
|
||||
|
||||
uint32_t
|
||||
sctp_select_a_tag(struct sctp_inpcb *inp, int save_in_twait)
|
||||
sctp_select_a_tag(struct sctp_inpcb *inp, uint16_t lport, uint16_t rport, int save_in_twait)
|
||||
{
|
||||
u_long x, not_done;
|
||||
struct timeval now;
|
||||
@ -861,7 +861,7 @@ sctp_select_a_tag(struct sctp_inpcb *inp, int save_in_twait)
|
||||
/* we never use 0 */
|
||||
continue;
|
||||
}
|
||||
if (sctp_is_vtag_good(inp, x, &now, save_in_twait)) {
|
||||
if (sctp_is_vtag_good(inp, x, lport, rport, &now, save_in_twait)) {
|
||||
not_done = 0;
|
||||
}
|
||||
}
|
||||
@ -894,6 +894,8 @@ sctp_init_asoc(struct sctp_inpcb *m, struct sctp_tcb *stcb,
|
||||
asoc->heart_beat_delay = TICKS_TO_MSEC(m->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT]);
|
||||
asoc->cookie_life = m->sctp_ep.def_cookie_life;
|
||||
asoc->sctp_cmt_on_off = (uint8_t) SCTP_BASE_SYSCTL(sctp_cmt_on_off);
|
||||
/* EY Init nr_sack variable */
|
||||
asoc->sctp_nr_sack_on_off = (uint8_t) SCTP_BASE_SYSCTL(sctp_nr_sack_on_off);
|
||||
/* JRS 5/21/07 - Init CMT PF variables */
|
||||
asoc->sctp_cmt_pf = (uint8_t) SCTP_BASE_SYSCTL(sctp_cmt_pf);
|
||||
asoc->sctp_frag_point = m->sctp_frag_point;
|
||||
@ -910,7 +912,8 @@ sctp_init_asoc(struct sctp_inpcb *m, struct sctp_tcb *stcb,
|
||||
#endif
|
||||
asoc->sb_send_resv = 0;
|
||||
if (override_tag) {
|
||||
if (sctp_is_in_timewait(override_tag)) {
|
||||
#ifdef MICHAELS_EXPERIMENT
|
||||
if (sctp_is_in_timewait(override_tag, stcb->sctp_ep->sctp_lport, stcb->rport)) {
|
||||
/*
|
||||
* It must be in the time-wait hash, we put it there
|
||||
* when we aloc one. If not the peer is playing
|
||||
@ -924,13 +927,15 @@ sctp_init_asoc(struct sctp_inpcb *m, struct sctp_tcb *stcb,
|
||||
#endif
|
||||
return (ENOMEM);
|
||||
}
|
||||
|
||||
#else
|
||||
asoc->my_vtag = override_tag;
|
||||
#endif
|
||||
} else {
|
||||
asoc->my_vtag = sctp_select_a_tag(m, 1);
|
||||
asoc->my_vtag = sctp_select_a_tag(m, stcb->sctp_ep->sctp_lport, stcb->rport, 1);
|
||||
}
|
||||
/* Get the nonce tags */
|
||||
asoc->my_vtag_nonce = sctp_select_a_tag(m, 0);
|
||||
asoc->peer_vtag_nonce = sctp_select_a_tag(m, 0);
|
||||
asoc->my_vtag_nonce = sctp_select_a_tag(m, stcb->sctp_ep->sctp_lport, stcb->rport, 0);
|
||||
asoc->peer_vtag_nonce = sctp_select_a_tag(m, stcb->sctp_ep->sctp_lport, stcb->rport, 0);
|
||||
asoc->vrf_id = vrf_id;
|
||||
|
||||
if (sctp_is_feature_on(m, SCTP_PCB_FLAGS_DONOT_HEARTBEAT))
|
||||
@ -951,13 +956,12 @@ sctp_init_asoc(struct sctp_inpcb *m, struct sctp_tcb *stcb,
|
||||
#endif
|
||||
asoc->refcnt = 0;
|
||||
asoc->assoc_up_sent = 0;
|
||||
asoc->assoc_id = asoc->my_vtag;
|
||||
asoc->asconf_seq_out = asoc->str_reset_seq_out = asoc->init_seq_number = asoc->sending_seq =
|
||||
sctp_select_initial_TSN(&m->sctp_ep);
|
||||
asoc->asconf_seq_out_acked = asoc->asconf_seq_out - 1;
|
||||
/* we are optimisitic here */
|
||||
asoc->peer_supports_pktdrop = 1;
|
||||
|
||||
asoc->peer_supports_nat = 0;
|
||||
asoc->sent_queue_retran_cnt = 0;
|
||||
|
||||
/* for CMT */
|
||||
@ -1146,6 +1150,17 @@ sctp_init_asoc(struct sctp_inpcb *m, struct sctp_tcb *stcb,
|
||||
return (ENOMEM);
|
||||
}
|
||||
memset(asoc->mapping_array, 0, asoc->mapping_array_size);
|
||||
/* EY - initialize the nr_mapping_array just like mapping array */
|
||||
asoc->nr_mapping_array_size = SCTP_INITIAL_NR_MAPPING_ARRAY;
|
||||
SCTP_MALLOC(asoc->nr_mapping_array, uint8_t *, asoc->nr_mapping_array_size,
|
||||
SCTP_M_MAP);
|
||||
/*
|
||||
* if (asoc->nr_mapping_array == NULL) { SCTP_FREE(asoc->strmout,
|
||||
* SCTP_M_STRMO); SCTP_LTRACE_ERR_RET(NULL, stcb, NULL,
|
||||
* SCTP_FROM_SCTPUTIL, ENOMEM); return (ENOMEM); }
|
||||
*/
|
||||
memset(asoc->nr_mapping_array, 0, asoc->nr_mapping_array_size);
|
||||
|
||||
/* Now the init of the other outqueues */
|
||||
TAILQ_INIT(&asoc->free_chunks);
|
||||
TAILQ_INIT(&asoc->out_wheel);
|
||||
@ -1159,6 +1174,7 @@ sctp_init_asoc(struct sctp_inpcb *m, struct sctp_tcb *stcb,
|
||||
TAILQ_INIT(&asoc->asconf_queue);
|
||||
/* authentication fields */
|
||||
asoc->authinfo.random = NULL;
|
||||
asoc->authinfo.active_keyid = 0;
|
||||
asoc->authinfo.assoc_key = NULL;
|
||||
asoc->authinfo.assoc_keyid = 0;
|
||||
asoc->authinfo.recv_key = NULL;
|
||||
@ -1204,6 +1220,30 @@ sctp_expand_mapping_array(struct sctp_association *asoc, uint32_t needed)
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* EY - nr_sack version of the above method */
|
||||
int
|
||||
sctp_expand_nr_mapping_array(struct sctp_association *asoc, uint32_t needed)
|
||||
{
|
||||
/* nr mapping array needs to grow */
|
||||
uint8_t *new_array;
|
||||
uint32_t new_size;
|
||||
|
||||
new_size = asoc->nr_mapping_array_size + ((needed + 7) / 8 + SCTP_NR_MAPPING_ARRAY_INCR);
|
||||
SCTP_MALLOC(new_array, uint8_t *, new_size, SCTP_M_MAP);
|
||||
if (new_array == NULL) {
|
||||
/* can't get more, forget it */
|
||||
SCTP_PRINTF("No memory for expansion of SCTP mapping array %d\n",
|
||||
new_size);
|
||||
return (-1);
|
||||
}
|
||||
memset(new_array, 0, new_size);
|
||||
memcpy(new_array, asoc->nr_mapping_array, asoc->nr_mapping_array_size);
|
||||
SCTP_FREE(asoc->nr_mapping_array, SCTP_M_MAP);
|
||||
asoc->nr_mapping_array = new_array;
|
||||
asoc->nr_mapping_array_size = new_size;
|
||||
return (0);
|
||||
}
|
||||
|
||||
#if defined(SCTP_USE_THREAD_BASED_ITERATOR)
|
||||
static void
|
||||
sctp_iterator_work(struct sctp_iterator *it)
|
||||
@ -1617,7 +1657,15 @@ sctp_timeout_handler(void *t)
|
||||
stcb->asoc.timosack++;
|
||||
if (stcb->asoc.cumulative_tsn != stcb->asoc.highest_tsn_inside_map)
|
||||
sctp_sack_check(stcb, 0, 0, &abort_flag);
|
||||
sctp_send_sack(stcb);
|
||||
|
||||
/*
|
||||
* EY if nr_sacks used then send an nr-sack , a sack
|
||||
* otherwise
|
||||
*/
|
||||
if (SCTP_BASE_SYSCTL(sctp_nr_sack_on_off) && stcb->asoc.peer_supports_nr_sack)
|
||||
sctp_send_nr_sack(stcb);
|
||||
else
|
||||
sctp_send_sack(stcb);
|
||||
}
|
||||
#ifdef SCTP_AUDITING_ENABLED
|
||||
sctp_auditing(4, inp, stcb, net);
|
||||
@ -2904,19 +2952,6 @@ sctp_notify_assoc_change(uint32_t event, struct sctp_tcb *stcb,
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* First if we are are going down dump everything we can to the
|
||||
* socket rcv queue.
|
||||
*/
|
||||
|
||||
if ((stcb == NULL) ||
|
||||
(stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) ||
|
||||
(stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) ||
|
||||
(stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET)
|
||||
) {
|
||||
/* If the socket is gone we are out of here */
|
||||
return;
|
||||
}
|
||||
/*
|
||||
* For TCP model AND UDP connected sockets we will send an error up
|
||||
* when an ABORT comes in.
|
||||
@ -3025,10 +3060,10 @@ sctp_notify_peer_addr_change(struct sctp_tcb *stcb, uint32_t state,
|
||||
struct sctp_paddr_change *spc;
|
||||
struct sctp_queued_to_read *control;
|
||||
|
||||
if ((stcb == NULL) || (sctp_is_feature_off(stcb->sctp_ep, SCTP_PCB_FLAGS_RECVPADDREVNT)))
|
||||
if (sctp_is_feature_off(stcb->sctp_ep, SCTP_PCB_FLAGS_RECVPADDREVNT)) {
|
||||
/* event not enabled */
|
||||
return;
|
||||
|
||||
}
|
||||
m_notify = sctp_get_mbuf_for_msg(sizeof(struct sctp_paddr_change), 0, M_DONTWAIT, 1, MT_DATA);
|
||||
if (m_notify == NULL)
|
||||
return;
|
||||
@ -3099,15 +3134,15 @@ sctp_notify_send_failed(struct sctp_tcb *stcb, uint32_t error,
|
||||
#endif
|
||||
)
|
||||
{
|
||||
struct mbuf *m_notify, *tt;
|
||||
struct mbuf *m_notify;
|
||||
struct sctp_send_failed *ssf;
|
||||
struct sctp_queued_to_read *control;
|
||||
int length;
|
||||
|
||||
if ((stcb == NULL) || (sctp_is_feature_off(stcb->sctp_ep, SCTP_PCB_FLAGS_RECVSENDFAILEVNT)))
|
||||
if (sctp_is_feature_off(stcb->sctp_ep, SCTP_PCB_FLAGS_RECVSENDFAILEVNT)) {
|
||||
/* event not enabled */
|
||||
return;
|
||||
|
||||
}
|
||||
m_notify = sctp_get_mbuf_for_msg(sizeof(struct sctp_send_failed), 0, M_DONTWAIT, 1, MT_DATA);
|
||||
if (m_notify == NULL)
|
||||
/* no space left */
|
||||
@ -3133,20 +3168,18 @@ sctp_notify_send_failed(struct sctp_tcb *stcb, uint32_t error,
|
||||
ssf->ssf_info.sinfo_assoc_id = sctp_get_associd(stcb);
|
||||
ssf->ssf_assoc_id = sctp_get_associd(stcb);
|
||||
|
||||
/* Take off the chunk header */
|
||||
m_adj(chk->data, sizeof(struct sctp_data_chunk));
|
||||
|
||||
/* trim out any 0 len mbufs */
|
||||
while (SCTP_BUF_LEN(chk->data) == 0) {
|
||||
tt = chk->data;
|
||||
chk->data = SCTP_BUF_NEXT(tt);
|
||||
SCTP_BUF_NEXT(tt) = NULL;
|
||||
sctp_m_freem(tt);
|
||||
}
|
||||
|
||||
SCTP_BUF_NEXT(m_notify) = chk->data;
|
||||
SCTP_BUF_LEN(m_notify) = sizeof(struct sctp_send_failed);
|
||||
|
||||
if (chk->data) {
|
||||
/*
|
||||
* trim off the sctp chunk header(it should be there)
|
||||
*/
|
||||
if (chk->send_size >= sizeof(struct sctp_data_chunk)) {
|
||||
m_adj(chk->data, sizeof(struct sctp_data_chunk));
|
||||
sctp_mbuf_crush(chk->data);
|
||||
chk->send_size -= sizeof(struct sctp_data_chunk);
|
||||
}
|
||||
}
|
||||
/* Steal off the mbuf */
|
||||
chk->data = NULL;
|
||||
/*
|
||||
@ -3187,10 +3220,10 @@ sctp_notify_send_failed2(struct sctp_tcb *stcb, uint32_t error,
|
||||
struct sctp_queued_to_read *control;
|
||||
int length;
|
||||
|
||||
if ((stcb == NULL) || (sctp_is_feature_off(stcb->sctp_ep, SCTP_PCB_FLAGS_RECVSENDFAILEVNT)))
|
||||
if (sctp_is_feature_off(stcb->sctp_ep, SCTP_PCB_FLAGS_RECVSENDFAILEVNT)) {
|
||||
/* event not enabled */
|
||||
return;
|
||||
|
||||
}
|
||||
length = sizeof(struct sctp_send_failed) + sp->length;
|
||||
m_notify = sctp_get_mbuf_for_msg(sizeof(struct sctp_send_failed), 0, M_DONTWAIT, 1, MT_DATA);
|
||||
if (m_notify == NULL)
|
||||
@ -3257,10 +3290,10 @@ sctp_notify_adaptation_layer(struct sctp_tcb *stcb,
|
||||
struct sctp_adaptation_event *sai;
|
||||
struct sctp_queued_to_read *control;
|
||||
|
||||
if ((stcb == NULL) || (sctp_is_feature_off(stcb->sctp_ep, SCTP_PCB_FLAGS_ADAPTATIONEVNT)))
|
||||
if (sctp_is_feature_off(stcb->sctp_ep, SCTP_PCB_FLAGS_ADAPTATIONEVNT)) {
|
||||
/* event not enabled */
|
||||
return;
|
||||
|
||||
}
|
||||
m_notify = sctp_get_mbuf_for_msg(sizeof(struct sctp_adaption_event), 0, M_DONTWAIT, 1, MT_DATA);
|
||||
if (m_notify == NULL)
|
||||
/* no space left */
|
||||
@ -3304,11 +3337,10 @@ sctp_notify_partial_delivery_indication(struct sctp_tcb *stcb, uint32_t error,
|
||||
struct sctp_queued_to_read *control;
|
||||
struct sockbuf *sb;
|
||||
|
||||
if ((stcb == NULL) || (stcb->sctp_socket == NULL) ||
|
||||
sctp_is_feature_off(stcb->sctp_ep, SCTP_PCB_FLAGS_PDAPIEVNT))
|
||||
if (sctp_is_feature_off(stcb->sctp_ep, SCTP_PCB_FLAGS_PDAPIEVNT)) {
|
||||
/* event not enabled */
|
||||
return;
|
||||
|
||||
}
|
||||
m_notify = sctp_get_mbuf_for_msg(sizeof(struct sctp_pdapi_event), 0, M_DONTWAIT, 1, MT_DATA);
|
||||
if (m_notify == NULL)
|
||||
/* no space left */
|
||||
@ -3378,9 +3410,6 @@ sctp_notify_shutdown_event(struct sctp_tcb *stcb)
|
||||
* For TCP model AND UDP connected sockets we will send an error up
|
||||
* when an SHUTDOWN completes
|
||||
*/
|
||||
if (stcb == NULL) {
|
||||
return;
|
||||
}
|
||||
if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
|
||||
(stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) {
|
||||
/* mark socket closed for read/write and wakeup! */
|
||||
@ -3404,10 +3433,10 @@ sctp_notify_shutdown_event(struct sctp_tcb *stcb)
|
||||
SCTP_SOCKET_UNLOCK(so, 1);
|
||||
#endif
|
||||
}
|
||||
if (sctp_is_feature_off(stcb->sctp_ep, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT))
|
||||
if (sctp_is_feature_off(stcb->sctp_ep, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT)) {
|
||||
/* event not enabled */
|
||||
return;
|
||||
|
||||
}
|
||||
m_notify = sctp_get_mbuf_for_msg(sizeof(struct sctp_shutdown_event), 0, M_DONTWAIT, 1, MT_DATA);
|
||||
if (m_notify == NULL)
|
||||
/* no space left */
|
||||
@ -3439,6 +3468,53 @@ sctp_notify_shutdown_event(struct sctp_tcb *stcb)
|
||||
&stcb->sctp_socket->so_rcv, 1, SCTP_SO_NOT_LOCKED);
|
||||
}
|
||||
|
||||
static void
|
||||
sctp_notify_sender_dry_event(struct sctp_tcb *stcb,
|
||||
int so_locked
|
||||
#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
|
||||
SCTP_UNUSED
|
||||
#endif
|
||||
)
|
||||
{
|
||||
struct mbuf *m_notify;
|
||||
struct sctp_sender_dry_event *event;
|
||||
struct sctp_queued_to_read *control;
|
||||
|
||||
if (sctp_is_feature_off(stcb->sctp_ep, SCTP_PCB_FLAGS_DRYEVNT)) {
|
||||
/* event not enabled */
|
||||
return;
|
||||
}
|
||||
m_notify = sctp_get_mbuf_for_msg(sizeof(struct sctp_sender_dry_event), 0, M_DONTWAIT, 1, MT_DATA);
|
||||
if (m_notify == NULL) {
|
||||
/* no space left */
|
||||
return;
|
||||
}
|
||||
SCTP_BUF_LEN(m_notify) = 0;
|
||||
event = mtod(m_notify, struct sctp_sender_dry_event *);
|
||||
event->sender_dry_type = SCTP_SENDER_DRY_EVENT;
|
||||
event->sender_dry_flags = 0;
|
||||
event->sender_dry_length = sizeof(struct sctp_sender_dry_event);
|
||||
event->sender_dry_assoc_id = sctp_get_associd(stcb);
|
||||
|
||||
SCTP_BUF_LEN(m_notify) = sizeof(struct sctp_sender_dry_event);
|
||||
SCTP_BUF_NEXT(m_notify) = NULL;
|
||||
|
||||
/* append to socket */
|
||||
control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination,
|
||||
0, 0, 0, 0, 0, 0, m_notify);
|
||||
if (control == NULL) {
|
||||
/* no memory */
|
||||
sctp_m_freem(m_notify);
|
||||
return;
|
||||
}
|
||||
control->length = SCTP_BUF_LEN(m_notify);
|
||||
control->spec_flags = M_NOTIFICATION;
|
||||
/* not that we need this */
|
||||
control->tail_mbuf = m_notify;
|
||||
sctp_add_to_readq(stcb->sctp_ep, stcb, control,
|
||||
&stcb->sctp_socket->so_rcv, 1, so_locked);
|
||||
}
|
||||
|
||||
static void
|
||||
sctp_notify_stream_reset(struct sctp_tcb *stcb,
|
||||
int number_entries, uint16_t * list, int flag)
|
||||
@ -3448,13 +3524,10 @@ sctp_notify_stream_reset(struct sctp_tcb *stcb,
|
||||
struct sctp_stream_reset_event *strreset;
|
||||
int len;
|
||||
|
||||
if (stcb == NULL) {
|
||||
return;
|
||||
}
|
||||
if (sctp_is_feature_off(stcb->sctp_ep, SCTP_PCB_FLAGS_STREAM_RESETEVNT))
|
||||
if (sctp_is_feature_off(stcb->sctp_ep, SCTP_PCB_FLAGS_STREAM_RESETEVNT)) {
|
||||
/* event not enabled */
|
||||
return;
|
||||
|
||||
}
|
||||
m_notify = sctp_get_mbuf_for_msg(MCLBYTES, 0, M_DONTWAIT, 1, MT_DATA);
|
||||
if (m_notify == NULL)
|
||||
/* no space left */
|
||||
@ -3516,19 +3589,11 @@ sctp_ulp_notify(uint32_t notification, struct sctp_tcb *stcb,
|
||||
#endif
|
||||
)
|
||||
{
|
||||
if (stcb == NULL) {
|
||||
/* unlikely but */
|
||||
return;
|
||||
}
|
||||
if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) ||
|
||||
if ((stcb == NULL) ||
|
||||
(stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) ||
|
||||
(stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) ||
|
||||
(stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET)
|
||||
) {
|
||||
/* No notifications up when we are in a no socket state */
|
||||
return;
|
||||
}
|
||||
if (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET) {
|
||||
/* Can't send up to a closed socket any notifications */
|
||||
(stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET)) {
|
||||
/* If the socket is gone we are out of here */
|
||||
return;
|
||||
}
|
||||
if (stcb && ((stcb->asoc.state & SCTP_STATE_COOKIE_WAIT) ||
|
||||
@ -3549,6 +3614,10 @@ sctp_ulp_notify(uint32_t notification, struct sctp_tcb *stcb,
|
||||
if (stcb->asoc.adaptation_needed && (stcb->asoc.adaptation_sent == 0)) {
|
||||
sctp_notify_adaptation_layer(stcb, error);
|
||||
}
|
||||
if (stcb->asoc.peer_supports_auth == 0) {
|
||||
sctp_ulp_notify(SCTP_NOTIFY_NO_PEER_AUTH, stcb, 0,
|
||||
NULL, so_locked);
|
||||
}
|
||||
break;
|
||||
case SCTP_NOTIFY_ASSOC_DOWN:
|
||||
sctp_notify_assoc_change(SCTP_SHUTDOWN_COMP, stcb, error, NULL, so_locked);
|
||||
@ -3613,6 +3682,10 @@ sctp_ulp_notify(uint32_t notification, struct sctp_tcb *stcb,
|
||||
break;
|
||||
case SCTP_NOTIFY_ASSOC_RESTART:
|
||||
sctp_notify_assoc_change(SCTP_RESTART, stcb, error, data, so_locked);
|
||||
if (stcb->asoc.peer_supports_auth == 0) {
|
||||
sctp_ulp_notify(SCTP_NOTIFY_NO_PEER_AUTH, stcb, 0,
|
||||
NULL, so_locked);
|
||||
}
|
||||
break;
|
||||
case SCTP_NOTIFY_HB_RESP:
|
||||
break;
|
||||
@ -3651,16 +3724,22 @@ sctp_ulp_notify(uint32_t notification, struct sctp_tcb *stcb,
|
||||
break;
|
||||
case SCTP_NOTIFY_AUTH_NEW_KEY:
|
||||
sctp_notify_authentication(stcb, SCTP_AUTH_NEWKEY, error,
|
||||
(uint16_t) (uintptr_t) data);
|
||||
(uint16_t) (uintptr_t) data,
|
||||
so_locked);
|
||||
break;
|
||||
#if 0
|
||||
case SCTP_NOTIFY_AUTH_KEY_CONFLICT:
|
||||
sctp_notify_authentication(stcb, SCTP_AUTH_KEY_CONFLICT,
|
||||
error, (uint16_t) (uintptr_t) data);
|
||||
case SCTP_NOTIFY_AUTH_FREE_KEY:
|
||||
sctp_notify_authentication(stcb, SCTP_AUTH_FREE_KEY, error,
|
||||
(uint16_t) (uintptr_t) data,
|
||||
so_locked);
|
||||
break;
|
||||
case SCTP_NOTIFY_NO_PEER_AUTH:
|
||||
sctp_notify_authentication(stcb, SCTP_AUTH_NO_AUTH, error,
|
||||
(uint16_t) (uintptr_t) data,
|
||||
so_locked);
|
||||
break;
|
||||
case SCTP_NOTIFY_SENDER_DRY:
|
||||
sctp_notify_sender_dry_event(stcb, so_locked);
|
||||
break;
|
||||
#endif /* not yet? remove? */
|
||||
|
||||
|
||||
default:
|
||||
SCTPDBG(SCTP_DEBUG_UTIL1, "%s: unknown notification %xh (%u)\n",
|
||||
__FUNCTION__, notification, notification);
|
||||
@ -3701,17 +3780,6 @@ sctp_report_all_outbound(struct sctp_tcb *stcb, int holds_lock, int so_locked
|
||||
while (chk) {
|
||||
TAILQ_REMOVE(&asoc->sent_queue, chk, sctp_next);
|
||||
asoc->sent_queue_cnt--;
|
||||
if (chk->data) {
|
||||
/*
|
||||
* trim off the sctp chunk header(it should
|
||||
* be there)
|
||||
*/
|
||||
if (chk->send_size >= sizeof(struct sctp_data_chunk)) {
|
||||
m_adj(chk->data, sizeof(struct sctp_data_chunk));
|
||||
sctp_mbuf_crush(chk->data);
|
||||
chk->send_size -= sizeof(struct sctp_data_chunk);
|
||||
}
|
||||
}
|
||||
sctp_free_bufspace(stcb, asoc, chk, 1);
|
||||
sctp_ulp_notify(SCTP_NOTIFY_DG_FAIL, stcb,
|
||||
SCTP_NOTIFY_DATAGRAM_SENT, chk, so_locked);
|
||||
@ -3730,17 +3798,6 @@ sctp_report_all_outbound(struct sctp_tcb *stcb, int holds_lock, int so_locked
|
||||
while (chk) {
|
||||
TAILQ_REMOVE(&asoc->send_queue, chk, sctp_next);
|
||||
asoc->send_queue_cnt--;
|
||||
if (chk->data) {
|
||||
/*
|
||||
* trim off the sctp chunk header(it should
|
||||
* be there)
|
||||
*/
|
||||
if (chk->send_size >= sizeof(struct sctp_data_chunk)) {
|
||||
m_adj(chk->data, sizeof(struct sctp_data_chunk));
|
||||
sctp_mbuf_crush(chk->data);
|
||||
chk->send_size -= sizeof(struct sctp_data_chunk);
|
||||
}
|
||||
}
|
||||
sctp_free_bufspace(stcb, asoc, chk, 1);
|
||||
sctp_ulp_notify(SCTP_NOTIFY_DG_FAIL, stcb, SCTP_NOTIFY_DATAGRAM_UNSENT, chk, so_locked);
|
||||
if (chk->data) {
|
||||
@ -4355,7 +4412,6 @@ sctp_pull_off_control_to_new_inp(struct sctp_inpcb *old_inp,
|
||||
SCTP_INP_READ_UNLOCK(new_inp);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
sctp_add_to_readq(struct sctp_inpcb *inp,
|
||||
struct sctp_tcb *stcb,
|
||||
@ -4687,7 +4743,9 @@ sctp_release_pr_sctp_chunk(struct sctp_tcb *stcb, struct sctp_tmit_chunk *tp1,
|
||||
|
||||
#endif
|
||||
sctp_free_bufspace(stcb, &stcb->asoc, tp1, 1);
|
||||
sctp_ulp_notify(SCTP_NOTIFY_DG_FAIL, stcb, reason, tp1, SCTP_SO_NOT_LOCKED);
|
||||
sctp_flight_size_decrease(tp1);
|
||||
sctp_total_flight_decrease(stcb, tp1);
|
||||
sctp_ulp_notify(SCTP_NOTIFY_DG_FAIL, stcb, reason, tp1, so_locked);
|
||||
sctp_m_freem(tp1->data);
|
||||
tp1->data = NULL;
|
||||
#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
|
||||
@ -4970,7 +5028,15 @@ sctp_user_rcvd(struct sctp_tcb *stcb, uint32_t * freed_so_far, int hold_rlock,
|
||||
goto out;
|
||||
}
|
||||
SCTP_STAT_INCR(sctps_wu_sacks_sent);
|
||||
sctp_send_sack(stcb);
|
||||
/*
|
||||
* EY if nr_sacks used then send an nr-sack , a sack
|
||||
* otherwise
|
||||
*/
|
||||
if (SCTP_BASE_SYSCTL(sctp_nr_sack_on_off) && stcb->asoc.peer_supports_nr_sack)
|
||||
sctp_send_nr_sack(stcb);
|
||||
else
|
||||
sctp_send_sack(stcb);
|
||||
|
||||
sctp_chunk_output(stcb->sctp_ep, stcb,
|
||||
SCTP_OUTPUT_FROM_USR_RCVD, SCTP_SO_LOCKED);
|
||||
/* make sure no timer is running */
|
||||
|
@ -77,7 +77,7 @@ struct sctp_ifa *
|
||||
|
||||
uint32_t sctp_select_initial_TSN(struct sctp_pcb *);
|
||||
|
||||
uint32_t sctp_select_a_tag(struct sctp_inpcb *, int);
|
||||
uint32_t sctp_select_a_tag(struct sctp_inpcb *, uint16_t lport, uint16_t rport, int);
|
||||
|
||||
int sctp_init_asoc(struct sctp_inpcb *, struct sctp_tcb *, int, uint32_t, uint32_t);
|
||||
|
||||
@ -168,6 +168,8 @@ sctp_report_all_outbound(struct sctp_tcb *, int, int
|
||||
|
||||
int sctp_expand_mapping_array(struct sctp_association *, uint32_t);
|
||||
|
||||
/* EY nr_sack version of the above method, expands nr_mapping_array */
|
||||
int sctp_expand_nr_mapping_array(struct sctp_association *, uint32_t);
|
||||
void
|
||||
sctp_abort_notification(struct sctp_tcb *, int, int
|
||||
#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
|
||||
|
@ -286,6 +286,9 @@ sctp6_notify_mbuf(struct sctp_inpcb *inp, struct icmp6_hdr *icmp6,
|
||||
/* Adjust destination size limit */
|
||||
if (net->mtu > nxtsz) {
|
||||
net->mtu = nxtsz;
|
||||
if (net->port) {
|
||||
net->mtu -= sizeof(struct udphdr);
|
||||
}
|
||||
}
|
||||
/* now what about the ep? */
|
||||
if (stcb->asoc.smallest_mtu > nxtsz) {
|
||||
|
Loading…
Reference in New Issue
Block a user