Changeset View
Changeset View
Standalone View
Standalone View
sys/dev/wg/wg_noise.c
Show First 20 Lines • Show All 557 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
void | void | ||||
noise_remote_keypairs_clear(struct noise_remote *r) | noise_remote_keypairs_clear(struct noise_remote *r) | ||||
{ | { | ||||
struct noise_keypair *kp; | struct noise_keypair *kp; | ||||
mtx_lock(&r->r_keypair_mtx); | mtx_lock(&r->r_keypair_mtx); | ||||
kp = ck_pr_load_ptr(&r->r_next); | kp = r->r_next; | ||||
ck_pr_store_ptr(&r->r_next, NULL); | r->r_next = NULL; | ||||
noise_keypair_drop(kp); | noise_keypair_drop(kp); | ||||
kp = ck_pr_load_ptr(&r->r_current); | kp = r->r_current; | ||||
ck_pr_store_ptr(&r->r_current, NULL); | r->r_current = NULL; | ||||
noise_keypair_drop(kp); | noise_keypair_drop(kp); | ||||
kp = ck_pr_load_ptr(&r->r_previous); | kp = r->r_previous; | ||||
ck_pr_store_ptr(&r->r_previous, NULL); | r->r_previous = NULL; | ||||
noise_keypair_drop(kp); | noise_keypair_drop(kp); | ||||
mtx_unlock(&r->r_keypair_mtx); | mtx_unlock(&r->r_keypair_mtx); | ||||
} | } | ||||
static void | static void | ||||
noise_remote_expire_current(struct noise_remote *r) | noise_remote_expire_current(struct noise_remote *r) | ||||
{ | { | ||||
struct epoch_tracker et; | struct epoch_tracker et; | ||||
struct noise_keypair *kp; | struct noise_keypair *kp; | ||||
noise_remote_handshake_clear(r); | noise_remote_handshake_clear(r); | ||||
NET_EPOCH_ENTER(et); | NET_EPOCH_ENTER(et); | ||||
kp = ck_pr_load_ptr(&r->r_next); | kp = r->r_next; | ||||
jhb: Possibly these two should remain as atomics as they are used to provide READ_ONCE semantics. | |||||
if (kp != NULL) | if (kp != NULL) | ||||
ck_pr_store_bool(&kp->kp_can_send, false); | ck_pr_store_bool(&kp->kp_can_send, false); | ||||
kp = ck_pr_load_ptr(&r->r_current); | kp = r->r_current; | ||||
if (kp != NULL) | if (kp != NULL) | ||||
ck_pr_store_bool(&kp->kp_can_send, false); | ck_pr_store_bool(&kp->kp_can_send, false); | ||||
NET_EPOCH_EXIT(et); | NET_EPOCH_EXIT(et); | ||||
} | } | ||||
/* Keypair functions */ | /* Keypair functions */ | ||||
static void | static void | ||||
noise_add_new_keypair(struct noise_local *l, struct noise_remote *r, | noise_add_new_keypair(struct noise_local *l, struct noise_remote *r, | ||||
struct noise_keypair *kp) | struct noise_keypair *kp) | ||||
{ | { | ||||
struct noise_keypair *next, *current, *previous; | struct noise_keypair *next, *current, *previous; | ||||
struct noise_index *r_i = &r->r_index; | struct noise_index *r_i = &r->r_index; | ||||
/* Insert into the keypair table */ | /* Insert into the keypair table */ | ||||
mtx_lock(&r->r_keypair_mtx); | mtx_lock(&r->r_keypair_mtx); | ||||
next = ck_pr_load_ptr(&r->r_next); | next = r->r_next; | ||||
current = ck_pr_load_ptr(&r->r_current); | current = r->r_current; | ||||
previous = ck_pr_load_ptr(&r->r_previous); | previous = r->r_previous; | ||||
if (kp->kp_is_initiator) { | if (kp->kp_is_initiator) { | ||||
if (next != NULL) { | if (next != NULL) { | ||||
ck_pr_store_ptr(&r->r_next, NULL); | r->r_next = NULL; | ||||
ck_pr_store_ptr(&r->r_previous, next); | r->r_previous = next; | ||||
noise_keypair_drop(current); | noise_keypair_drop(current); | ||||
} else { | } else { | ||||
ck_pr_store_ptr(&r->r_previous, current); | r->r_previous = current; | ||||
} | } | ||||
noise_keypair_drop(previous); | noise_keypair_drop(previous); | ||||
ck_pr_store_ptr(&r->r_current, kp); | r->r_current = kp; | ||||
} else { | } else { | ||||
ck_pr_store_ptr(&r->r_next, kp); | r->r_next = kp; | ||||
noise_keypair_drop(next); | noise_keypair_drop(next); | ||||
ck_pr_store_ptr(&r->r_previous, NULL); | r->r_previous = NULL; | ||||
noise_keypair_drop(previous); | noise_keypair_drop(previous); | ||||
} | } | ||||
mtx_unlock(&r->r_keypair_mtx); | mtx_unlock(&r->r_keypair_mtx); | ||||
/* Insert into index table */ | /* Insert into index table */ | ||||
rw_assert(&r->r_handshake_lock, RA_WLOCKED); | rw_assert(&r->r_handshake_lock, RA_WLOCKED); | ||||
▲ Show 20 Lines • Show All 64 Lines • ▼ Show 20 Lines | |||||
struct noise_keypair * | struct noise_keypair * | ||||
noise_keypair_current(struct noise_remote *r) | noise_keypair_current(struct noise_remote *r) | ||||
{ | { | ||||
struct epoch_tracker et; | struct epoch_tracker et; | ||||
struct noise_keypair *kp, *ret = NULL; | struct noise_keypair *kp, *ret = NULL; | ||||
NET_EPOCH_ENTER(et); | NET_EPOCH_ENTER(et); | ||||
kp = ck_pr_load_ptr(&r->r_current); | kp = r->r_current; | ||||
jhbAuthorUnsubmitted Done Inline ActionsAnother READ_ONCE jhb: Another READ_ONCE | |||||
if (kp != NULL && ck_pr_load_bool(&kp->kp_can_send)) { | if (kp != NULL && ck_pr_load_bool(&kp->kp_can_send)) { | ||||
if (noise_timer_expired(kp->kp_birthdate, REJECT_AFTER_TIME, 0)) | if (noise_timer_expired(kp->kp_birthdate, REJECT_AFTER_TIME, 0)) | ||||
ck_pr_store_bool(&kp->kp_can_send, false); | ck_pr_store_bool(&kp->kp_can_send, false); | ||||
else if (refcount_acquire_if_not_zero(&kp->kp_refcnt)) | else if (refcount_acquire_if_not_zero(&kp->kp_refcnt)) | ||||
ret = kp; | ret = kp; | ||||
} | } | ||||
NET_EPOCH_EXIT(et); | NET_EPOCH_EXIT(et); | ||||
return (ret); | return (ret); | ||||
} | } | ||||
struct noise_keypair * | struct noise_keypair * | ||||
noise_keypair_ref(struct noise_keypair *kp) | noise_keypair_ref(struct noise_keypair *kp) | ||||
{ | { | ||||
refcount_acquire(&kp->kp_refcnt); | refcount_acquire(&kp->kp_refcnt); | ||||
return (kp); | return (kp); | ||||
} | } | ||||
int | int | ||||
noise_keypair_received_with(struct noise_keypair *kp) | noise_keypair_received_with(struct noise_keypair *kp) | ||||
{ | { | ||||
struct noise_keypair *old; | struct noise_keypair *old; | ||||
struct noise_remote *r = kp->kp_remote; | struct noise_remote *r = kp->kp_remote; | ||||
if (kp != ck_pr_load_ptr(&r->r_next)) | if (kp != r->r_next) | ||||
jhbAuthorUnsubmitted Done Inline ActionsThis is the unlocked read and it's just an optimization to avoid the lock below (and not an uncommon pattern, so I think it is obvious in context) jhb: This is the unlocked read and it's just an optimization to avoid the lock below (and not an… | |||||
emasteUnsubmitted Not Done Inline ActionsFair enough, I did not look at each case to find the unlocked read and when pointed out in context it's clear enough to me. [That said I don't think a comment wouldn't be out of place] emaste: Fair enough, I did not look at each case to find the unlocked read and when pointed out in… | |||||
return (0); | return (0); | ||||
mtx_lock(&r->r_keypair_mtx); | mtx_lock(&r->r_keypair_mtx); | ||||
if (kp != ck_pr_load_ptr(&r->r_next)) { | if (kp != r->r_next) { | ||||
mtx_unlock(&r->r_keypair_mtx); | mtx_unlock(&r->r_keypair_mtx); | ||||
return (0); | return (0); | ||||
} | } | ||||
old = ck_pr_load_ptr(&r->r_previous); | old = r->r_previous; | ||||
ck_pr_store_ptr(&r->r_previous, ck_pr_load_ptr(&r->r_current)); | r->r_previous = r->r_current; | ||||
noise_keypair_drop(old); | noise_keypair_drop(old); | ||||
ck_pr_store_ptr(&r->r_current, kp); | r->r_current = kp; | ||||
ck_pr_store_ptr(&r->r_next, NULL); | r->r_next = NULL; | ||||
mtx_unlock(&r->r_keypair_mtx); | mtx_unlock(&r->r_keypair_mtx); | ||||
return (ECONNRESET); | return (ECONNRESET); | ||||
} | } | ||||
static void | static void | ||||
noise_keypair_smr_free(struct epoch_context *smr) | noise_keypair_smr_free(struct epoch_context *smr) | ||||
{ | { | ||||
▲ Show 20 Lines • Show All 105 Lines • ▼ Show 20 Lines | |||||
noise_keep_key_fresh_send(struct noise_remote *r) | noise_keep_key_fresh_send(struct noise_remote *r) | ||||
{ | { | ||||
struct epoch_tracker et; | struct epoch_tracker et; | ||||
struct noise_keypair *current; | struct noise_keypair *current; | ||||
int keep_key_fresh; | int keep_key_fresh; | ||||
uint64_t nonce; | uint64_t nonce; | ||||
NET_EPOCH_ENTER(et); | NET_EPOCH_ENTER(et); | ||||
current = ck_pr_load_ptr(&r->r_current); | current = r->r_current; | ||||
jhbAuthorUnsubmitted Done Inline ActionsAnother READ_ONCE jhb: Another READ_ONCE | |||||
keep_key_fresh = current != NULL && ck_pr_load_bool(¤t->kp_can_send); | keep_key_fresh = current != NULL && ck_pr_load_bool(¤t->kp_can_send); | ||||
if (!keep_key_fresh) | if (!keep_key_fresh) | ||||
goto out; | goto out; | ||||
#ifdef __LP64__ | #ifdef __LP64__ | ||||
nonce = ck_pr_load_64(¤t->kp_nonce_send); | nonce = ck_pr_load_64(¤t->kp_nonce_send); | ||||
#else | #else | ||||
rw_rlock(¤t->kp_nonce_lock); | rw_rlock(¤t->kp_nonce_lock); | ||||
nonce = current->kp_nonce_send; | nonce = current->kp_nonce_send; | ||||
Show All 12 Lines | |||||
int | int | ||||
noise_keep_key_fresh_recv(struct noise_remote *r) | noise_keep_key_fresh_recv(struct noise_remote *r) | ||||
{ | { | ||||
struct epoch_tracker et; | struct epoch_tracker et; | ||||
struct noise_keypair *current; | struct noise_keypair *current; | ||||
int keep_key_fresh; | int keep_key_fresh; | ||||
NET_EPOCH_ENTER(et); | NET_EPOCH_ENTER(et); | ||||
current = ck_pr_load_ptr(&r->r_current); | current = r->r_current; | ||||
jhbAuthorUnsubmitted Done Inline ActionsAnother READ_ONCE jhb: Another READ_ONCE | |||||
keep_key_fresh = current != NULL && ck_pr_load_bool(¤t->kp_can_send) && | keep_key_fresh = current != NULL && ck_pr_load_bool(¤t->kp_can_send) && | ||||
current->kp_is_initiator && noise_timer_expired(current->kp_birthdate, | current->kp_is_initiator && noise_timer_expired(current->kp_birthdate, | ||||
REJECT_AFTER_TIME - KEEPALIVE_TIMEOUT - REKEY_TIMEOUT, 0); | REJECT_AFTER_TIME - KEEPALIVE_TIMEOUT - REKEY_TIMEOUT, 0); | ||||
NET_EPOCH_EXIT(et); | NET_EPOCH_EXIT(et); | ||||
return (keep_key_fresh ? ESTALE : 0); | return (keep_key_fresh ? ESTALE : 0); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 507 Lines • Show Last 20 Lines |
Possibly these two should remain as atomics as they are used to provide READ_ONCE semantics.