svn commit: r188532 - in stable/7/sys: . netinet netinet6
Randall Stewart
rrs at FreeBSD.org
Thu Feb 12 10:50:28 PST 2009
Author: rrs
Date: Thu Feb 12 18:50:27 2009
New Revision: 188532
URL: http://svn.freebsd.org/changeset/base/188532
Log:
MFC of 185694 - The IETF hack session:
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 :-)
Modified:
stable/7/sys/ (props changed)
stable/7/sys/netinet/sctp.h
stable/7/sys/netinet/sctp_asconf.c
stable/7/sys/netinet/sctp_asconf.h
stable/7/sys/netinet/sctp_auth.c
stable/7/sys/netinet/sctp_auth.h
stable/7/sys/netinet/sctp_constants.h
stable/7/sys/netinet/sctp_header.h
stable/7/sys/netinet/sctp_indata.c
stable/7/sys/netinet/sctp_indata.h
stable/7/sys/netinet/sctp_input.c
stable/7/sys/netinet/sctp_os_bsd.h
stable/7/sys/netinet/sctp_output.c
stable/7/sys/netinet/sctp_output.h
stable/7/sys/netinet/sctp_pcb.c
stable/7/sys/netinet/sctp_pcb.h
stable/7/sys/netinet/sctp_structs.h
stable/7/sys/netinet/sctp_sysctl.c
stable/7/sys/netinet/sctp_sysctl.h
stable/7/sys/netinet/sctp_timer.c
stable/7/sys/netinet/sctp_uio.h
stable/7/sys/netinet/sctp_usrreq.c
stable/7/sys/netinet/sctp_var.h
stable/7/sys/netinet/sctputil.c
stable/7/sys/netinet/sctputil.h
stable/7/sys/netinet6/sctp6_usrreq.c
Modified: stable/7/sys/netinet/sctp.h
==============================================================================
--- stable/7/sys/netinet/sctp.h Thu Feb 12 18:33:56 2009 (r188531)
+++ stable/7/sys/netinet/sctp.h Thu Feb 12 18:50:27 2009 (r188532)
@@ -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
Modified: stable/7/sys/netinet/sctp_asconf.c
==============================================================================
--- stable/7/sys/netinet/sctp_asconf.c Thu Feb 12 18:33:56 2009 (r188531)
+++ stable/7/sys/netinet/sctp_asconf.c Thu Feb 12 18:50:27 2009 (r188532)
@@ -761,6 +761,9 @@ sctp_handle_asconf(struct mbuf *m, unsig
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 *
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_
"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 *stc
* 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 *
}
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);
+}
Modified: stable/7/sys/netinet/sctp_asconf.h
==============================================================================
--- stable/7/sys/netinet/sctp_asconf.h Thu Feb 12 18:33:56 2009 (r188531)
+++ stable/7/sys/netinet/sctp_asconf.h Thu Feb 12 18:50:27 2009 (r188532)
@@ -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 *);
Modified: stable/7/sys/netinet/sctp_auth.c
==============================================================================
--- stable/7/sys/netinet/sctp_auth.c Thu Feb 12 18:33:56 2009 (r188531)
+++ stable/7/sys/netinet/sctp_auth.c Thu Feb 12 18:50:27 2009 (r188532)
@@ -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 key
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
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_key
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 *
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
} /* 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
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_hmaclis
}
-/*
- * 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 *s
}
}
-/*
+/*-
* 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_inp
}
}
-/*
- * 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 *s
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 *s
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 *s
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_inp
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_in
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_
/* 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_
*/
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,
/* 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,
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,
#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_
}
}
-/*
- * 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,
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,
* *)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,
*/
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_t
/* 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_
}
}
/* 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 =
*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
More information about the svn-src-all
mailing list