aboutsummaryrefslogtreecommitdiffstats
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
parentBugfixes (diff)
downloadwireguard-openbsd-0a5977e6b12d5c6b9f19812d5e860c5f9eab4de4.tar.xz
wireguard-openbsd-0a5977e6b12d5c6b9f19812d5e860c5f9eab4de4.zip
Remove refcnt from fixedmap
-rw-r--r--src/fixedmap.h14
-rw-r--r--src/kern_wg.c38
-rw-r--r--src/wireguard.c136
-rw-r--r--src/wireguard.h4
4 files changed, 96 insertions, 96 deletions
diff --git a/src/fixedmap.h b/src/fixedmap.h
index d56a9b7..8398177 100644
--- a/src/fixedmap.h
+++ b/src/fixedmap.h
@@ -18,7 +18,6 @@
#define __FIXEDMAP_H__
#include <sys/types.h>
-#include <sys/refcnt.h>
#define FM_FOREACH(item, fm) \
for (item = (fm)->map; item < (fm)->map + (fm)->size; item++)
@@ -29,23 +28,20 @@
struct fixed_map {
size_t size;
- struct rwlock lock;
struct map_item {
enum {
FM_ITEM_EMPTY = 0,
FM_ITEM_FILLED,
} state;
uint32_t key;
- struct refcnt cnt;
void *value;
} *map;
};
-void fm_init(struct fixed_map *);
-void fm_destroy(struct fixed_map *);
-uint32_t fm_insert(struct fixed_map *, void *);
-void *fm_ref(struct fixed_map *, uint32_t);
-void fm_put(struct fixed_map *, uint32_t);
-void fm_remove(struct fixed_map *, uint32_t);
+void fm_init(struct fixed_map *);
+void fm_destroy(struct fixed_map *);
+uint32_t fm_insert(struct fixed_map *, void *);
+void *fm_lookup(struct fixed_map *, uint32_t);
+void fm_remove(struct fixed_map *, uint32_t);
#endif /* __FIXEDMAP_H__ */
diff --git a/src/kern_wg.c b/src/kern_wg.c
index 63eb6a3..8d3296f 100644
--- a/src/kern_wg.c
+++ b/src/kern_wg.c
@@ -168,7 +168,6 @@ void
fm_init(struct fixed_map *fm)
{
bzero(fm, sizeof(*fm));
- rw_init(&fm->lock, "fixedmap");
fm_resize(fm, 128);
}
@@ -179,8 +178,6 @@ fm_resize(struct fixed_map *fm, size_t size)
size_t osize;
struct map_item *omap;
- /* No lock as fm_resize is only called in fm_init (no lock) or
- * fm_insert (already locked) */
osize = fm->size;
omap = fm->map;
@@ -198,10 +195,6 @@ fm_resize(struct fixed_map *fm, size_t size)
void
fm_destroy(struct fixed_map *fm)
{
- struct map_item *item;
- /* No lock, as this is the last reference */
- FM_FOREACH_FILLED(item, fm)
- refcnt_finalize(&item->cnt, "fm_wait");
free(fm->map, M_DEVBUF, 0);
}
@@ -210,7 +203,6 @@ fm_insert(struct fixed_map *fm, void *v)
{
struct map_item *item = NULL, *iter;
- rw_enter_write(&fm->lock);
retry:
FM_FOREACH_EMPTY(iter, fm) {
item = iter;
@@ -226,39 +218,19 @@ retry:
item->key = (arc4random() & ~(fm->size - 1)) + (item - fm->map);
item->state = FM_ITEM_FILLED;
item->value = v;
- refcnt_init(&item->cnt);
-
- rw_exit_write(&fm->lock);
return item->key;
}
-void
-fm_put(struct fixed_map *fm, uint32_t k)
-{
- struct map_item *item;
-
- rw_enter_read(&fm->lock);
- item = fm->map + (k & (fm->size - 1));
- if (item->key != k)
- panic("unexpected key, should exist");
- refcnt_rele_wake(&item->cnt);
- rw_exit_read(&fm->lock);
-}
-
void *
-fm_ref(struct fixed_map *fm, uint32_t k)
+fm_lookup(struct fixed_map *fm, uint32_t k)
{
void *v = NULL;
struct map_item *item;
- rw_enter_read(&fm->lock);
item = fm->map + (k & (fm->size - 1));
- if (item->key == k) {
+ if (item->key == k)
v = item->value;
- refcnt_take(&item->cnt);
- }
- rw_exit_read(&fm->lock);
return v;
}
@@ -267,17 +239,11 @@ fm_remove(struct fixed_map *fm, uint32_t k)
{
struct map_item *item;
- rw_enter_read(&fm->lock);
item = fm->map + (k & (fm->size - 1));
- refcnt_finalize(&item->cnt, "fm_wait");
- rw_exit_read(&fm->lock);
-
- rw_enter_write(&fm->lock);
if (item->key == k) {
item->state = FM_ITEM_EMPTY;
item->value = NULL;
}
- rw_exit_write(&fm->lock);
}
/*
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 */
diff --git a/src/wireguard.h b/src/wireguard.h
index 5b64457..7853ba6 100644
--- a/src/wireguard.h
+++ b/src/wireguard.h
@@ -149,7 +149,8 @@ struct wg_session {
uint32_t s_local_id; /* Static */
uint32_t s_remote_id; /* Static */
struct wg_peer *s_peer; /* Static */
- struct timespec s_created;
+ struct timespec s_created; /* Static */
+ struct refcnt s_refcnt; /* Atomic */
/* All protected by s_lock */
struct rwlock s_lock;
@@ -178,6 +179,7 @@ struct wg_peer {
void *p_arg;
struct wg_device *p_device;
struct wg_pubkey p_remote;
+ struct refcnt p_refcnt;
SLIST_ENTRY(wg_peer) p_entry;
/* All protected by p_lock */