aboutsummaryrefslogtreecommitdiffstats
path: root/src/wireguard.c
diff options
context:
space:
mode:
authorMatt Dunwoodie <ncon@mail.noconroy.net>2019-10-02 02:46:59 +0100
committerMatt Dunwoodie <ncon@mail.noconroy.net>2019-10-02 02:46:59 +0100
commit0a5977e6b12d5c6b9f19812d5e860c5f9eab4de4 (patch)
tree21aacd4bbc1ca31effd12c46441f0d048f3d69ce /src/wireguard.c
parentBugfixes (diff)
downloadwireguard-openbsd-0a5977e6b12d5c6b9f19812d5e860c5f9eab4de4.tar.xz
wireguard-openbsd-0a5977e6b12d5c6b9f19812d5e860c5f9eab4de4.zip
Remove refcnt from fixedmap
Diffstat (limited to 'src/wireguard.c')
-rw-r--r--src/wireguard.c136
1 files changed, 86 insertions, 50 deletions
diff --git a/src/wireguard.c b/src/wireguard.c
index 6c049b6..c830d10 100644
--- a/src/wireguard.c
+++ b/src/wireguard.c
@@ -18,6 +18,7 @@
#include <sys/malloc.h>
#include <sys/systm.h>
#include <sys/rwlock.h>
+#include <sys/refcnt.h>
#include <sys/time.h>
#include <sys/antireplay.h>
#include <lib/libkern/libkern.h>
@@ -90,14 +91,6 @@ wg_device_init(struct wg_device *dev,
/* d_cookie_maker, d_keypair initialised to 0 */
}
-void
-wg_device_setkey(struct wg_device *dev, struct wg_privkey *key)
-{
- rw_enter_write(&dev->d_lock);
- wg_keypair_from_key(&dev->d_keypair, key);
- rw_exit_write(&dev->d_lock);
-}
-
struct wg_peer *
wg_device_new_peer(struct wg_device *dev, struct wg_pubkey *key, void *arg)
{
@@ -107,11 +100,14 @@ wg_device_new_peer(struct wg_device *dev, struct wg_pubkey *key, void *arg)
peer->p_arg = arg;
peer->p_device = dev;
peer->p_remote = *key;
+ refcnt_init(&peer->p_refcnt);
rw_init(&peer->p_lock, "wg_peer");
+ rw_enter_write(&dev->d_lock);
rw_enter_write(&peer->p_lock);
peer->p_id = fm_insert(&dev->d_peers, peer);
rw_exit_write(&peer->p_lock);
+ rw_exit_write(&dev->d_lock);
/* All other elements of wg_peer are nulled by M_ZERO */
return peer;
@@ -124,89 +120,112 @@ wg_device_new_session(struct wg_device *dev)
session = malloc(sizeof(*session), M_DEVBUF, M_WAITOK | M_ZERO);
getnanotime(&session->s_created);
+ refcnt_init(&session->s_refcnt);
+ rw_enter_write(&dev->d_lock);
rw_enter_write(&session->s_lock);
session->s_local_id = fm_insert(&dev->d_sessions, session);
rw_exit_write(&session->s_lock);
+ rw_exit_write(&dev->d_lock);
return session;
}
struct wg_peer *
-wg_device_ref_peerid(struct wg_device *dev, uint32_t id)
-{
- return fm_ref(&dev->d_peers, id);
-}
-
-struct wg_peer *
wg_device_ref_peerkey(struct wg_device *dev, struct wg_pubkey *key)
{
/* For the time being, we just iterate through peers to find the
* matching peer */
- uint32_t id = 0;
struct wg_peer *peer;
struct map_item *item;
- rw_enter_read(&dev->d_peers.lock);
+ rw_enter_read(&dev->d_lock);
FM_FOREACH_FILLED(item, &dev->d_peers) {
peer = item->value;
if (memcmp(key->k, peer->p_remote.k, sizeof(key->k)) == 0)
- id = peer->p_id;
+ break;
+ else
+ peer = NULL;
}
- rw_exit_read(&dev->d_peers.lock);
+ rw_exit_read(&dev->d_lock);
+
+ if (peer)
+ wg_peer_ref(peer);
- /* Take reference and return peer */
- return wg_device_ref_peerid(dev, id);
+ return peer;
+}
+
+struct wg_peer *
+wg_device_ref_peerid(struct wg_device *dev, uint32_t id)
+{
+ struct wg_peer *peer;
+ rw_enter_read(&dev->d_lock);
+ peer = fm_lookup(&dev->d_peers, id);
+ if (peer)
+ refcnt_take(&peer->p_refcnt);
+ rw_exit_read(&dev->d_lock);
+ return peer;
}
void
wg_peer_ref(struct wg_peer *peer)
{
- /* Don't return anything, just take a reference and expect it exists */
- KASSERT(wg_device_ref_peerid(peer->p_device, peer->p_id) != NULL);
+ refcnt_take(&peer->p_refcnt);
}
void
wg_peer_put(struct wg_peer *peer)
{
- fm_put(&peer->p_device->d_peers, peer->p_id);
+ refcnt_rele_wake(&peer->p_refcnt);
}
void
wg_peer_drop(struct wg_peer *peer)
{
+ rw_enter_write(&peer->p_device->d_lock);
fm_remove(&peer->p_device->d_peers, peer->p_id);
+ rw_exit_write(&peer->p_device->d_lock);
+ refcnt_finalize(&peer->p_refcnt, "wg_peer drop");
free(peer, M_DEVBUF, sizeof(*peer));
}
struct wg_session *
wg_device_ref_session(struct wg_device *dev, uint32_t id)
{
- return fm_ref(&dev->d_sessions, id);
+ struct wg_session *session;
+ rw_enter_read(&dev->d_lock);
+ session = fm_lookup(&dev->d_sessions, id);
+ if (session)
+ refcnt_take(&session->s_refcnt);
+ rw_exit_read(&dev->d_lock);
+ return session;
}
void
wg_session_ref(struct wg_session *session)
{
- KASSERT(wg_device_ref_session(session->s_peer->p_device,
- session->s_local_id) != NULL);
+ refcnt_take(&session->s_refcnt);
}
void
wg_session_put(struct wg_session *session)
{
- fm_put(&session->s_peer->p_device->d_sessions, session->s_local_id);
+ refcnt_rele_wake(&session->s_refcnt);
}
void
wg_session_drop(struct wg_session *session)
{
+ rw_enter_write(&session->s_peer->p_device->d_lock);
fm_remove(&session->s_peer->p_device->d_sessions, session->s_local_id);
+ rw_exit_write(&session->s_peer->p_device->d_lock);
+ refcnt_finalize(&session->s_refcnt, "wg_session drop");
free(session, M_DEVBUF, sizeof(*session));
}
void
wg_peer_attach_session(struct wg_peer *peer, struct wg_session *session)
{
+ struct wg_session *old_session;
/* Assert the session is not attached to another peer.
* Assert the session is for the same device that the peer is for.
* Assert the session is newly created, by checking s_state. */
@@ -216,26 +235,24 @@ wg_peer_attach_session(struct wg_peer *peer, struct wg_session *session)
session->s_state == WG_STATE_MADE_INITIATION);
rw_enter_write(&peer->p_lock);
- if (peer->p_hs_session) {
- wg_session_drop(peer->p_hs_session);
- peer->p_hs_session = NULL;
- }
-
- peer->p_hs_session = session;
session->s_peer = peer;
+ old_session = peer->p_hs_session;
+ peer->p_hs_session = session;
rw_exit_write(&peer->p_lock);
+
+ if (old_session)
+ wg_session_drop(old_session);
}
void
wg_session_promote(struct wg_session *session)
{
- /* TODO check locking state before */
+ struct wg_session *old_session;
struct wg_peer *peer = session->s_peer;
struct wg_keyset *ks = &session->s_keyset;
struct wg_handshake *hs = &session->s_handshake;
/* Setup session: derive keys, initialise the antireplay structure */
- rw_enter_write(&peer->p_lock);
rw_enter_write(&session->s_lock);
if (session->s_state == WG_STATE_RECV_RESPONSE) {
session->s_state = WG_STATE_INITIATOR;
@@ -244,31 +261,36 @@ wg_session_promote(struct wg_session *session)
session->s_state = WG_STATE_RESPONDER;
wg_kdf(ks->k_rxkey.k, ks->k_txkey.k, NULL, hs->h_ck, NULL, 0);
} else {
- goto leave;
+ rw_exit_write(&session->s_lock);
+ return;
}
antireplay_init(&ks->k_ar);
+ rw_exit_write(&session->s_lock);
- /* Move session to p_ks_session by shuffling older sessions. */
- if (peer->p_ks_session_old != NULL)
- wg_session_drop(peer->p_ks_session_old);
+ rw_enter_write(&session->s_lock);
+ old_session = peer->p_ks_session_old;
if (peer->p_ks_session != NULL)
peer->p_ks_session_old = peer->p_ks_session;
peer->p_ks_session = peer->p_hs_session;
peer->p_hs_session = NULL;
-leave:
rw_exit_write(&session->s_lock);
- rw_exit_write(&peer->p_lock);
+
+ if (old_session != NULL)
+ wg_session_drop(old_session);
}
struct wg_session *
wg_peer_hs_session(struct wg_peer *peer)
{
struct wg_session *session;
+
rw_enter_read(&peer->p_lock);
- if ((session = peer->p_hs_session) != NULL)
- wg_session_ref(session);
+ session = peer->p_hs_session;
rw_exit_read(&peer->p_lock);
+
+ if (session)
+ wg_session_ref(session);
return session;
}
@@ -282,13 +304,21 @@ wg_peer_ks_session(struct wg_peer *peer)
(wg_timespec_timedout(&session->s_created, WG_REJECT_AFTER_TIME) ||
session->s_keyset.k_txcounter > WG_REJECT_AFTER_MESSAGES))
session = NULL;
+ rw_exit_read(&peer->p_lock);
if (session != NULL)
wg_session_ref(session);
- rw_exit_read(&peer->p_lock);
return session;
}
void
+wg_device_setkey(struct wg_device *dev, struct wg_privkey *key)
+{
+ rw_enter_write(&dev->d_lock);
+ wg_keypair_from_key(&dev->d_keypair, key);
+ rw_exit_write(&dev->d_lock);
+}
+
+void
wg_peer_setshared(struct wg_peer *peer, struct wg_privkey *key)
{
rw_enter_write(&peer->p_lock);
@@ -318,20 +348,26 @@ wg_peer_last_handshake(struct wg_peer *peer)
void
wg_peer_clean(struct wg_peer *peer)
{
+ struct wg_session *hs, *ks, *ks_old;
rw_enter_write(&peer->p_lock);
- if (peer->p_hs_session != NULL)
- wg_session_drop(peer->p_hs_session);
- if (peer->p_ks_session != NULL)
- wg_session_drop(peer->p_ks_session);
- if (peer->p_ks_session_old != NULL)
- wg_session_drop(peer->p_ks_session_old);
+ hs = peer->p_hs_session;
+ ks = peer->p_ks_session;
+ ks_old = peer->p_ks_session_old;
peer->p_hs_session = NULL;
peer->p_ks_session = NULL;
peer->p_ks_session_old = NULL;
rw_enter_write(&peer->p_lock);
+
+ if (hs != NULL)
+ wg_session_drop(hs);
+ if (ks != NULL)
+ wg_session_drop(ks);
+ if (ks_old != NULL)
+ wg_session_drop(ks_old);
+
}
/* Crypto */