Mon Aug 31 20:23:56 2020 UTC ()
wg: Use thmap(9) for peer and session lookup.

Make sure we also don't trip over our own shoelaces by choosing the
same session index twice.


(riastradh)
diff -r1.36 -r1.37 src/sys/net/if_wg.c

cvs diff -r1.36 -r1.37 src/sys/net/if_wg.c (expand / switch to unified diff)

--- src/sys/net/if_wg.c 2020/08/31 20:21:30 1.36
+++ src/sys/net/if_wg.c 2020/08/31 20:23:56 1.37
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: if_wg.c,v 1.36 2020/08/31 20:21:30 riastradh Exp $ */ 1/* $NetBSD: if_wg.c,v 1.37 2020/08/31 20:23:56 riastradh Exp $ */
2 2
3/* 3/*
4 * Copyright (C) Ryota Ozaki <ozaki.ryota@gmail.com> 4 * Copyright (C) Ryota Ozaki <ozaki.ryota@gmail.com>
5 * All rights reserved. 5 * All rights reserved.
6 * 6 *
7 * Redistribution and use in source and binary forms, with or without 7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions 8 * modification, are permitted provided that the following conditions
9 * are met: 9 * are met:
10 * 1. Redistributions of source code must retain the above copyright 10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer. 11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright 12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the 13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution. 14 * documentation and/or other materials provided with the distribution.
@@ -31,27 +31,27 @@ @@ -31,27 +31,27 @@
31 31
32/* 32/*
33 * This network interface aims to implement the WireGuard protocol. 33 * This network interface aims to implement the WireGuard protocol.
34 * The implementation is based on the paper of WireGuard as of 34 * The implementation is based on the paper of WireGuard as of
35 * 2018-06-30 [1]. The paper is referred in the source code with label 35 * 2018-06-30 [1]. The paper is referred in the source code with label
36 * [W]. Also the specification of the Noise protocol framework as of 36 * [W]. Also the specification of the Noise protocol framework as of
37 * 2018-07-11 [2] is referred with label [N]. 37 * 2018-07-11 [2] is referred with label [N].
38 * 38 *
39 * [1] https://www.wireguard.com/papers/wireguard.pdf 39 * [1] https://www.wireguard.com/papers/wireguard.pdf
40 * [2] http://noiseprotocol.org/noise.pdf 40 * [2] http://noiseprotocol.org/noise.pdf
41 */ 41 */
42 42
43#include <sys/cdefs.h> 43#include <sys/cdefs.h>
44__KERNEL_RCSID(0, "$NetBSD: if_wg.c,v 1.36 2020/08/31 20:21:30 riastradh Exp $"); 44__KERNEL_RCSID(0, "$NetBSD: if_wg.c,v 1.37 2020/08/31 20:23:56 riastradh Exp $");
45 45
46#ifdef _KERNEL_OPT 46#ifdef _KERNEL_OPT
47#include "opt_inet.h" 47#include "opt_inet.h"
48#endif 48#endif
49 49
50#include <sys/param.h> 50#include <sys/param.h>
51#include <sys/types.h> 51#include <sys/types.h>
52 52
53#include <sys/atomic.h> 53#include <sys/atomic.h>
54#include <sys/callout.h> 54#include <sys/callout.h>
55#include <sys/cprng.h> 55#include <sys/cprng.h>
56#include <sys/cpu.h> 56#include <sys/cpu.h>
57#include <sys/device.h> 57#include <sys/device.h>
@@ -67,26 +67,27 @@ __KERNEL_RCSID(0, "$NetBSD: if_wg.c,v 1. @@ -67,26 +67,27 @@ __KERNEL_RCSID(0, "$NetBSD: if_wg.c,v 1.
67#include <sys/mutex.h> 67#include <sys/mutex.h>
68#include <sys/pcq.h> 68#include <sys/pcq.h>
69#include <sys/percpu.h> 69#include <sys/percpu.h>
70#include <sys/pserialize.h> 70#include <sys/pserialize.h>
71#include <sys/psref.h> 71#include <sys/psref.h>
72#include <sys/queue.h> 72#include <sys/queue.h>
73#include <sys/rwlock.h> 73#include <sys/rwlock.h>
74#include <sys/socket.h> 74#include <sys/socket.h>
75#include <sys/socketvar.h> 75#include <sys/socketvar.h>
76#include <sys/sockio.h> 76#include <sys/sockio.h>
77#include <sys/sysctl.h> 77#include <sys/sysctl.h>
78#include <sys/syslog.h> 78#include <sys/syslog.h>
79#include <sys/systm.h> 79#include <sys/systm.h>
 80#include <sys/thmap.h>
80#include <sys/time.h> 81#include <sys/time.h>
81#include <sys/timespec.h> 82#include <sys/timespec.h>
82 83
83#include <net/bpf.h> 84#include <net/bpf.h>
84#include <net/if.h> 85#include <net/if.h>
85#include <net/if_types.h> 86#include <net/if_types.h>
86#include <net/if_wg.h> 87#include <net/if_wg.h>
87#include <net/route.h> 88#include <net/route.h>
88 89
89#include <netinet/in.h> 90#include <netinet/in.h>
90#include <netinet/in_pcb.h> 91#include <netinet/in_pcb.h>
91#include <netinet/in_var.h> 92#include <netinet/in_var.h>
92#include <netinet/ip.h> 93#include <netinet/ip.h>
@@ -593,26 +594,29 @@ struct wg_peer { @@ -593,26 +594,29 @@ struct wg_peer {
593struct wg_ops; 594struct wg_ops;
594 595
595struct wg_softc { 596struct wg_softc {
596 struct ifnet wg_if; 597 struct ifnet wg_if;
597 LIST_ENTRY(wg_softc) wg_list; 598 LIST_ENTRY(wg_softc) wg_list;
598 kmutex_t *wg_lock; 599 kmutex_t *wg_lock;
599 krwlock_t *wg_rwlock; 600 krwlock_t *wg_rwlock;
600 601
601 uint8_t wg_privkey[WG_STATIC_KEY_LEN]; 602 uint8_t wg_privkey[WG_STATIC_KEY_LEN];
602 uint8_t wg_pubkey[WG_STATIC_KEY_LEN]; 603 uint8_t wg_pubkey[WG_STATIC_KEY_LEN];
603 604
604 int wg_npeers; 605 int wg_npeers;
605 struct pslist_head wg_peers; 606 struct pslist_head wg_peers;
 607 struct thmap *wg_peers_bypubkey;
 608 struct thmap *wg_peers_byname;
 609 struct thmap *wg_sessions_byindex;
606 uint16_t wg_listen_port; 610 uint16_t wg_listen_port;
607 611
608 struct wg_worker *wg_worker; 612 struct wg_worker *wg_worker;
609 lwp_t *wg_worker_lwp; 613 lwp_t *wg_worker_lwp;
610 614
611 struct radix_node_head *wg_rtable_ipv4; 615 struct radix_node_head *wg_rtable_ipv4;
612 struct radix_node_head *wg_rtable_ipv6; 616 struct radix_node_head *wg_rtable_ipv6;
613 617
614 struct wg_ppsratecheck wg_ppsratecheck; 618 struct wg_ppsratecheck wg_ppsratecheck;
615 619
616 struct wg_ops *wg_ops; 620 struct wg_ops *wg_ops;
617 621
618#ifdef WG_RUMPKERNEL 622#ifdef WG_RUMPKERNEL
@@ -1149,26 +1153,72 @@ wg_lock_unstable_session(struct wg_peer  @@ -1149,26 +1153,72 @@ wg_lock_unstable_session(struct wg_peer
1149 mutex_exit(wgp->wgp_lock); 1153 mutex_exit(wgp->wgp_lock);
1150 return wgs; 1154 return wgs;
1151} 1155}
1152 1156
1153#if 0 1157#if 0
1154static void 1158static void
1155wg_unlock_session(struct wg_peer *wgp, struct wg_session *wgs) 1159wg_unlock_session(struct wg_peer *wgp, struct wg_session *wgs)
1156{ 1160{
1157 1161
1158 mutex_exit(wgs->wgs_lock); 1162 mutex_exit(wgs->wgs_lock);
1159} 1163}
1160#endif 1164#endif
1161 1165
 1166static uint32_t
 1167wg_assign_sender_index(struct wg_softc *wg, struct wg_session *wgs)
 1168{
 1169 struct wg_peer *wgp = wgs->wgs_peer;
 1170 struct wg_session *wgs0;
 1171 uint32_t index;
 1172 void *garbage;
 1173
 1174 mutex_enter(wgs->wgs_lock);
 1175
 1176 /* Release the current index, if there is one. */
 1177 while ((index = wgs->wgs_sender_index) != 0) {
 1178 /* Remove the session by index. */
 1179 thmap_del(wg->wg_sessions_byindex, &index, sizeof index);
 1180 wgs->wgs_sender_index = 0;
 1181 mutex_exit(wgs->wgs_lock);
 1182
 1183 /* Wait for all thmap_gets to complete, and GC. */
 1184 garbage = thmap_stage_gc(wg->wg_sessions_byindex);
 1185 mutex_enter(wgs->wgs_peer->wgp_lock);
 1186 pserialize_perform(wgp->wgp_psz);
 1187 mutex_exit(wgs->wgs_peer->wgp_lock);
 1188 thmap_gc(wg->wg_sessions_byindex, garbage);
 1189
 1190 mutex_enter(wgs->wgs_lock);
 1191 }
 1192
 1193restart:
 1194 /* Pick a uniform random nonzero index. */
 1195 while (__predict_false((index = cprng_strong32()) == 0))
 1196 continue;
 1197
 1198 /* Try to take it. */
 1199 wgs->wgs_sender_index = index;
 1200 wgs0 = thmap_put(wg->wg_sessions_byindex,
 1201 &wgs->wgs_sender_index, sizeof wgs->wgs_sender_index, wgs);
 1202
 1203 /* If someone else beat us, start over. */
 1204 if (__predict_false(wgs0 != wgs))
 1205 goto restart;
 1206
 1207 mutex_exit(wgs->wgs_lock);
 1208
 1209 return index;
 1210}
 1211
1162/* 1212/*
1163 * Handshake patterns 1213 * Handshake patterns
1164 * 1214 *
1165 * [W] 5: "These messages use the "IK" pattern from Noise" 1215 * [W] 5: "These messages use the "IK" pattern from Noise"
1166 * [N] 7.5. Interactive handshake patterns (fundamental) 1216 * [N] 7.5. Interactive handshake patterns (fundamental)
1167 * "The first character refers to the initiator’s static key:" 1217 * "The first character refers to the initiator’s static key:"
1168 * "I = Static key for initiator Immediately transmitted to responder, 1218 * "I = Static key for initiator Immediately transmitted to responder,
1169 * despite reduced or absent identity hiding" 1219 * despite reduced or absent identity hiding"
1170 * "The second character refers to the responder’s static key:" 1220 * "The second character refers to the responder’s static key:"
1171 * "K = Static key for responder Known to initiator" 1221 * "K = Static key for responder Known to initiator"
1172 * "IK: 1222 * "IK:
1173 * <- s 1223 * <- s
1174 * ... 1224 * ...
@@ -1182,27 +1232,27 @@ wg_unlock_session(struct wg_peer *wgp, s @@ -1182,27 +1232,27 @@ wg_unlock_session(struct wg_peer *wgp, s
1182 * <- e, ee, se, psk" 1232 * <- e, ee, se, psk"
1183 */ 1233 */
1184static void 1234static void
1185wg_fill_msg_init(struct wg_softc *wg, struct wg_peer *wgp, 1235wg_fill_msg_init(struct wg_softc *wg, struct wg_peer *wgp,
1186 struct wg_session *wgs, struct wg_msg_init *wgmi) 1236 struct wg_session *wgs, struct wg_msg_init *wgmi)
1187{ 1237{
1188 uint8_t ckey[WG_CHAINING_KEY_LEN]; /* [W] 5.4.2: Ci */ 1238 uint8_t ckey[WG_CHAINING_KEY_LEN]; /* [W] 5.4.2: Ci */
1189 uint8_t hash[WG_HASH_LEN]; /* [W] 5.4.2: Hi */ 1239 uint8_t hash[WG_HASH_LEN]; /* [W] 5.4.2: Hi */
1190 uint8_t cipher_key[WG_CIPHER_KEY_LEN]; 1240 uint8_t cipher_key[WG_CIPHER_KEY_LEN];
1191 uint8_t pubkey[WG_EPHEMERAL_KEY_LEN]; 1241 uint8_t pubkey[WG_EPHEMERAL_KEY_LEN];
1192 uint8_t privkey[WG_EPHEMERAL_KEY_LEN]; 1242 uint8_t privkey[WG_EPHEMERAL_KEY_LEN];
1193 1243
1194 wgmi->wgmi_type = WG_MSG_TYPE_INIT; 1244 wgmi->wgmi_type = WG_MSG_TYPE_INIT;
1195 wgmi->wgmi_sender = cprng_strong32(); 1245 wgmi->wgmi_sender = wg_assign_sender_index(wg, wgs);
1196 1246
1197 /* [W] 5.4.2: First Message: Initiator to Responder */ 1247 /* [W] 5.4.2: First Message: Initiator to Responder */
1198 1248
1199 /* Ci := HASH(CONSTRUCTION) */ 1249 /* Ci := HASH(CONSTRUCTION) */
1200 /* Hi := HASH(Ci || IDENTIFIER) */ 1250 /* Hi := HASH(Ci || IDENTIFIER) */
1201 wg_init_key_and_hash(ckey, hash); 1251 wg_init_key_and_hash(ckey, hash);
1202 /* Hi := HASH(Hi || Sr^pub) */ 1252 /* Hi := HASH(Hi || Sr^pub) */
1203 wg_algo_hash(hash, wgp->wgp_pubkey, sizeof(wgp->wgp_pubkey)); 1253 wg_algo_hash(hash, wgp->wgp_pubkey, sizeof(wgp->wgp_pubkey));
1204 1254
1205 WG_DUMP_HASH("hash", hash); 1255 WG_DUMP_HASH("hash", hash);
1206 1256
1207 /* [N] 2.2: "e" */ 1257 /* [N] 2.2: "e" */
1208 /* Ei^priv, Ei^pub := DH-GENERATE() */ 1258 /* Ei^priv, Ei^pub := DH-GENERATE() */
@@ -1257,27 +1307,26 @@ wg_fill_msg_init(struct wg_softc *wg, st @@ -1257,27 +1307,26 @@ wg_fill_msg_init(struct wg_softc *wg, st
1257 memset(wgmi->wgmi_mac2, 0, sizeof(wgmi->wgmi_mac2)); 1307 memset(wgmi->wgmi_mac2, 0, sizeof(wgmi->wgmi_mac2));
1258 else { 1308 else {
1259 wg_algo_mac(wgmi->wgmi_mac2, sizeof(wgmi->wgmi_mac2), 1309 wg_algo_mac(wgmi->wgmi_mac2, sizeof(wgmi->wgmi_mac2),
1260 wgp->wgp_latest_cookie, WG_COOKIE_LEN, 1310 wgp->wgp_latest_cookie, WG_COOKIE_LEN,
1261 (const uint8_t *)wgmi, 1311 (const uint8_t *)wgmi,
1262 offsetof(struct wg_msg_init, wgmi_mac2), 1312 offsetof(struct wg_msg_init, wgmi_mac2),
1263 NULL, 0); 1313 NULL, 0);
1264 } 1314 }
1265 1315
1266 memcpy(wgs->wgs_ephemeral_key_pub, pubkey, sizeof(pubkey)); 1316 memcpy(wgs->wgs_ephemeral_key_pub, pubkey, sizeof(pubkey));
1267 memcpy(wgs->wgs_ephemeral_key_priv, privkey, sizeof(privkey)); 1317 memcpy(wgs->wgs_ephemeral_key_priv, privkey, sizeof(privkey));
1268 memcpy(wgs->wgs_handshake_hash, hash, sizeof(hash)); 1318 memcpy(wgs->wgs_handshake_hash, hash, sizeof(hash));
1269 memcpy(wgs->wgs_chaining_key, ckey, sizeof(ckey)); 1319 memcpy(wgs->wgs_chaining_key, ckey, sizeof(ckey));
1270 wgs->wgs_sender_index = wgmi->wgmi_sender; 
1271 WG_DLOG("%s: sender=%x\n", __func__, wgs->wgs_sender_index); 1320 WG_DLOG("%s: sender=%x\n", __func__, wgs->wgs_sender_index);
1272} 1321}
1273 1322
1274static void 1323static void
1275wg_handle_msg_init(struct wg_softc *wg, const struct wg_msg_init *wgmi, 1324wg_handle_msg_init(struct wg_softc *wg, const struct wg_msg_init *wgmi,
1276 const struct sockaddr *src) 1325 const struct sockaddr *src)
1277{ 1326{
1278 uint8_t ckey[WG_CHAINING_KEY_LEN]; /* [W] 5.4.2: Ci */ 1327 uint8_t ckey[WG_CHAINING_KEY_LEN]; /* [W] 5.4.2: Ci */
1279 uint8_t hash[WG_HASH_LEN]; /* [W] 5.4.2: Hi */ 1328 uint8_t hash[WG_HASH_LEN]; /* [W] 5.4.2: Hi */
1280 uint8_t cipher_key[WG_CIPHER_KEY_LEN]; 1329 uint8_t cipher_key[WG_CIPHER_KEY_LEN];
1281 uint8_t peer_pubkey[WG_STATIC_KEY_LEN]; 1330 uint8_t peer_pubkey[WG_STATIC_KEY_LEN];
1282 struct wg_peer *wgp; 1331 struct wg_peer *wgp;
1283 struct wg_session *wgs; 1332 struct wg_session *wgs;
@@ -1599,27 +1648,27 @@ wg_fill_msg_resp(struct wg_softc *wg, st @@ -1599,27 +1648,27 @@ wg_fill_msg_resp(struct wg_softc *wg, st
1599 uint8_t ckey[WG_CHAINING_KEY_LEN]; /* [W] 5.4.3: Cr */ 1648 uint8_t ckey[WG_CHAINING_KEY_LEN]; /* [W] 5.4.3: Cr */
1600 uint8_t hash[WG_HASH_LEN]; /* [W] 5.4.3: Hr */ 1649 uint8_t hash[WG_HASH_LEN]; /* [W] 5.4.3: Hr */
1601 uint8_t cipher_key[WG_KDF_OUTPUT_LEN]; 1650 uint8_t cipher_key[WG_KDF_OUTPUT_LEN];
1602 uint8_t pubkey[WG_EPHEMERAL_KEY_LEN]; 1651 uint8_t pubkey[WG_EPHEMERAL_KEY_LEN];
1603 uint8_t privkey[WG_EPHEMERAL_KEY_LEN]; 1652 uint8_t privkey[WG_EPHEMERAL_KEY_LEN];
1604 struct wg_session *wgs; 1653 struct wg_session *wgs;
1605 struct psref psref; 1654 struct psref psref;
1606 1655
1607 wgs = wg_get_unstable_session(wgp, &psref); 1656 wgs = wg_get_unstable_session(wgp, &psref);
1608 memcpy(hash, wgs->wgs_handshake_hash, sizeof(hash)); 1657 memcpy(hash, wgs->wgs_handshake_hash, sizeof(hash));
1609 memcpy(ckey, wgs->wgs_chaining_key, sizeof(ckey)); 1658 memcpy(ckey, wgs->wgs_chaining_key, sizeof(ckey));
1610 1659
1611 wgmr->wgmr_type = WG_MSG_TYPE_RESP; 1660 wgmr->wgmr_type = WG_MSG_TYPE_RESP;
1612 wgmr->wgmr_sender = cprng_strong32(); 1661 wgmr->wgmr_sender = wg_assign_sender_index(wg, wgs);
1613 wgmr->wgmr_receiver = wgmi->wgmi_sender; 1662 wgmr->wgmr_receiver = wgmi->wgmi_sender;
1614 1663
1615 /* [W] 5.4.3 Second Message: Responder to Initiator */ 1664 /* [W] 5.4.3 Second Message: Responder to Initiator */
1616 1665
1617 /* [N] 2.2: "e" */ 1666 /* [N] 2.2: "e" */
1618 /* Er^priv, Er^pub := DH-GENERATE() */ 1667 /* Er^priv, Er^pub := DH-GENERATE() */
1619 wg_algo_generate_keypair(pubkey, privkey); 1668 wg_algo_generate_keypair(pubkey, privkey);
1620 /* Cr := KDF1(Cr, Er^pub) */ 1669 /* Cr := KDF1(Cr, Er^pub) */
1621 wg_algo_kdf(ckey, NULL, NULL, ckey, pubkey, sizeof(pubkey)); 1670 wg_algo_kdf(ckey, NULL, NULL, ckey, pubkey, sizeof(pubkey));
1622 /* msg.ephemeral := Er^pub */ 1671 /* msg.ephemeral := Er^pub */
1623 memcpy(wgmr->wgmr_ephemeral, pubkey, sizeof(wgmr->wgmr_ephemeral)); 1672 memcpy(wgmr->wgmr_ephemeral, pubkey, sizeof(wgmr->wgmr_ephemeral));
1624 /* Hr := HASH(Hr || msg.ephemeral) */ 1673 /* Hr := HASH(Hr || msg.ephemeral) */
1625 wg_algo_hash(hash, pubkey, sizeof(pubkey)); 1674 wg_algo_hash(hash, pubkey, sizeof(pubkey));
@@ -1670,27 +1719,26 @@ wg_fill_msg_resp(struct wg_softc *wg, st @@ -1670,27 +1719,26 @@ wg_fill_msg_resp(struct wg_softc *wg, st
1670 else { 1719 else {
1671 /* msg.mac2 := MAC(Lm, msg_b) */ 1720 /* msg.mac2 := MAC(Lm, msg_b) */
1672 wg_algo_mac(wgmr->wgmr_mac2, sizeof(wgmi->wgmi_mac2), 1721 wg_algo_mac(wgmr->wgmr_mac2, sizeof(wgmi->wgmi_mac2),
1673 wgp->wgp_latest_cookie, WG_COOKIE_LEN, 1722 wgp->wgp_latest_cookie, WG_COOKIE_LEN,
1674 (const uint8_t *)wgmr, 1723 (const uint8_t *)wgmr,
1675 offsetof(struct wg_msg_resp, wgmr_mac2), 1724 offsetof(struct wg_msg_resp, wgmr_mac2),
1676 NULL, 0); 1725 NULL, 0);
1677 } 1726 }
1678 1727
1679 memcpy(wgs->wgs_handshake_hash, hash, sizeof(hash)); 1728 memcpy(wgs->wgs_handshake_hash, hash, sizeof(hash));
1680 memcpy(wgs->wgs_chaining_key, ckey, sizeof(ckey)); 1729 memcpy(wgs->wgs_chaining_key, ckey, sizeof(ckey));
1681 memcpy(wgs->wgs_ephemeral_key_pub, pubkey, sizeof(pubkey)); 1730 memcpy(wgs->wgs_ephemeral_key_pub, pubkey, sizeof(pubkey));
1682 memcpy(wgs->wgs_ephemeral_key_priv, privkey, sizeof(privkey)); 1731 memcpy(wgs->wgs_ephemeral_key_priv, privkey, sizeof(privkey));
1683 wgs->wgs_sender_index = wgmr->wgmr_sender; 
1684 wgs->wgs_receiver_index = wgmi->wgmi_sender; 1732 wgs->wgs_receiver_index = wgmi->wgmi_sender;
1685 WG_DLOG("sender=%x\n", wgs->wgs_sender_index); 1733 WG_DLOG("sender=%x\n", wgs->wgs_sender_index);
1686 WG_DLOG("receiver=%x\n", wgs->wgs_receiver_index); 1734 WG_DLOG("receiver=%x\n", wgs->wgs_receiver_index);
1687 wg_put_session(wgs, &psref); 1735 wg_put_session(wgs, &psref);
1688} 1736}
1689 1737
1690static void 1738static void
1691wg_swap_sessions(struct wg_peer *wgp) 1739wg_swap_sessions(struct wg_peer *wgp)
1692{ 1740{
1693 1741
1694 KASSERT(mutex_owned(wgp->wgp_lock)); 1742 KASSERT(mutex_owned(wgp->wgp_lock));
1695 1743
1696 wgp->wgp_session_unstable = atomic_swap_ptr(&wgp->wgp_session_stable, 1744 wgp->wgp_session_unstable = atomic_swap_ptr(&wgp->wgp_session_stable,
@@ -1896,32 +1944,27 @@ wg_send_handshake_msg_resp(struct wg_sof @@ -1896,32 +1944,27 @@ wg_send_handshake_msg_resp(struct wg_sof
1896 error = wg->wg_ops->send_hs_msg(wgp, m); 1944 error = wg->wg_ops->send_hs_msg(wgp, m);
1897 if (error == 0) 1945 if (error == 0)
1898 WG_TRACE("resp msg sent"); 1946 WG_TRACE("resp msg sent");
1899 return error; 1947 return error;
1900} 1948}
1901 1949
1902static struct wg_peer * 1950static struct wg_peer *
1903wg_lookup_peer_by_pubkey(struct wg_softc *wg, 1951wg_lookup_peer_by_pubkey(struct wg_softc *wg,
1904 const uint8_t pubkey[WG_STATIC_KEY_LEN], struct psref *psref) 1952 const uint8_t pubkey[WG_STATIC_KEY_LEN], struct psref *psref)
1905{ 1953{
1906 struct wg_peer *wgp; 1954 struct wg_peer *wgp;
1907 1955
1908 int s = pserialize_read_enter(); 1956 int s = pserialize_read_enter();
1909 /* XXX O(n) */ 1957 wgp = thmap_get(wg->wg_peers_bypubkey, pubkey, WG_STATIC_KEY_LEN);
1910 WG_PEER_READER_FOREACH(wgp, wg) { 
1911 if (consttime_memequal(wgp->wgp_pubkey, pubkey, 
1912 sizeof(wgp->wgp_pubkey))) 
1913 break; 
1914 } 
1915 if (wgp != NULL) 1958 if (wgp != NULL)
1916 wg_get_peer(wgp, psref); 1959 wg_get_peer(wgp, psref);
1917 pserialize_read_exit(s); 1960 pserialize_read_exit(s);
1918 1961
1919 return wgp; 1962 return wgp;
1920} 1963}
1921 1964
1922static void 1965static void
1923wg_fill_msg_cookie(struct wg_softc *wg, struct wg_peer *wgp, 1966wg_fill_msg_cookie(struct wg_softc *wg, struct wg_peer *wgp,
1924 struct wg_msg_cookie *wgmc, const uint32_t sender, 1967 struct wg_msg_cookie *wgmc, const uint32_t sender,
1925 const uint8_t mac1[WG_MAC_LEN], const struct sockaddr *src) 1968 const uint8_t mac1[WG_MAC_LEN], const struct sockaddr *src)
1926{ 1969{
1927 uint8_t cookie[WG_COOKIE_LEN]; 1970 uint8_t cookie[WG_COOKIE_LEN];
@@ -2077,44 +2120,30 @@ wg_clear_states(struct wg_session *wgs) @@ -2077,44 +2120,30 @@ wg_clear_states(struct wg_session *wgs)
2077#define wgs_clear(v) explicit_memset(wgs->wgs_##v, 0, sizeof(wgs->wgs_##v)) 2120#define wgs_clear(v) explicit_memset(wgs->wgs_##v, 0, sizeof(wgs->wgs_##v))
2078 wgs_clear(handshake_hash); 2121 wgs_clear(handshake_hash);
2079 wgs_clear(chaining_key); 2122 wgs_clear(chaining_key);
2080 wgs_clear(ephemeral_key_pub); 2123 wgs_clear(ephemeral_key_pub);
2081 wgs_clear(ephemeral_key_priv); 2124 wgs_clear(ephemeral_key_priv);
2082 wgs_clear(ephemeral_key_peer); 2125 wgs_clear(ephemeral_key_peer);
2083#undef wgs_clear 2126#undef wgs_clear
2084} 2127}
2085 2128
2086static struct wg_session * 2129static struct wg_session *
2087wg_lookup_session_by_index(struct wg_softc *wg, const uint32_t index, 2130wg_lookup_session_by_index(struct wg_softc *wg, const uint32_t index,
2088 struct psref *psref) 2131 struct psref *psref)
2089{ 2132{
2090 struct wg_peer *wgp; 
2091 struct wg_session *wgs; 2133 struct wg_session *wgs;
2092 2134
2093 int s = pserialize_read_enter(); 2135 int s = pserialize_read_enter();
2094 /* XXX O(n) */ 2136 wgs = thmap_get(wg->wg_sessions_byindex, &index, sizeof index);
2095 WG_PEER_READER_FOREACH(wgp, wg) { 
2096 wgs = wgp->wgp_session_stable; 
2097 WG_DLOG("index=%x wgs_sender_index=%x\n", 
2098 index, wgs->wgs_sender_index); 
2099 if (wgs->wgs_sender_index == index) 
2100 break; 
2101 wgs = wgp->wgp_session_unstable; 
2102 WG_DLOG("index=%x wgs_sender_index=%x\n", 
2103 index, wgs->wgs_sender_index); 
2104 if (wgs->wgs_sender_index == index) 
2105 break; 
2106 wgs = NULL; 
2107 } 
2108 if (wgs != NULL) 2137 if (wgs != NULL)
2109 psref_acquire(psref, &wgs->wgs_psref, wg_psref_class); 2138 psref_acquire(psref, &wgs->wgs_psref, wg_psref_class);
2110 pserialize_read_exit(s); 2139 pserialize_read_exit(s);
2111 2140
2112 return wgs; 2141 return wgs;
2113} 2142}
2114 2143
2115static void 2144static void
2116wg_schedule_rekey_timer(struct wg_peer *wgp) 2145wg_schedule_rekey_timer(struct wg_peer *wgp)
2117{ 2146{
2118 int timeout = MIN(wg_rekey_after_time, INT_MAX/hz); 2147 int timeout = MIN(wg_rekey_after_time, INT_MAX/hz);
2119 2148
2120 callout_schedule(&wgp->wgp_rekey_timer, timeout * hz); 2149 callout_schedule(&wgp->wgp_rekey_timer, timeout * hz);
@@ -3252,137 +3281,178 @@ wg_alloc_peer(struct wg_softc *wg) @@ -3252,137 +3281,178 @@ wg_alloc_peer(struct wg_softc *wg)
3252 mutex_init(&wgs->wgs_send_counter_lock, MUTEX_DEFAULT, IPL_SOFTNET); 3281 mutex_init(&wgs->wgs_send_counter_lock, MUTEX_DEFAULT, IPL_SOFTNET);
3253#endif 3282#endif
3254 wgs->wgs_recvwin = kmem_zalloc(sizeof(*wgs->wgs_recvwin), KM_SLEEP); 3283 wgs->wgs_recvwin = kmem_zalloc(sizeof(*wgs->wgs_recvwin), KM_SLEEP);
3255 mutex_init(&wgs->wgs_recvwin->lock, MUTEX_DEFAULT, IPL_NONE); 3284 mutex_init(&wgs->wgs_recvwin->lock, MUTEX_DEFAULT, IPL_NONE);
3256 3285
3257 return wgp; 3286 return wgp;
3258} 3287}
3259 3288
3260static void 3289static void
3261wg_destroy_peer(struct wg_peer *wgp) 3290wg_destroy_peer(struct wg_peer *wgp)
3262{ 3291{
3263 struct wg_session *wgs; 3292 struct wg_session *wgs;
3264 struct wg_softc *wg = wgp->wgp_sc; 3293 struct wg_softc *wg = wgp->wgp_sc;
 3294 uint32_t index;
 3295 void *garbage;
3265 3296
 3297 /* Prevent new packets from this peer on any source address. */
3266 rw_enter(wg->wg_rwlock, RW_WRITER); 3298 rw_enter(wg->wg_rwlock, RW_WRITER);
3267 for (int i = 0; i < wgp->wgp_n_allowedips; i++) { 3299 for (int i = 0; i < wgp->wgp_n_allowedips; i++) {
3268 struct wg_allowedip *wga = &wgp->wgp_allowedips[i]; 3300 struct wg_allowedip *wga = &wgp->wgp_allowedips[i];
3269 struct radix_node_head *rnh = wg_rnh(wg, wga->wga_family); 3301 struct radix_node_head *rnh = wg_rnh(wg, wga->wga_family);
3270 struct radix_node *rn; 3302 struct radix_node *rn;
3271 3303
3272 KASSERT(rnh != NULL); 3304 KASSERT(rnh != NULL);
3273 rn = rnh->rnh_deladdr(&wga->wga_sa_addr, 3305 rn = rnh->rnh_deladdr(&wga->wga_sa_addr,
3274 &wga->wga_sa_mask, rnh); 3306 &wga->wga_sa_mask, rnh);
3275 if (rn == NULL) { 3307 if (rn == NULL) {
3276 char addrstr[128]; 3308 char addrstr[128];
3277 sockaddr_format(&wga->wga_sa_addr, addrstr, 3309 sockaddr_format(&wga->wga_sa_addr, addrstr,
3278 sizeof(addrstr)); 3310 sizeof(addrstr));
3279 WGLOG(LOG_WARNING, "Couldn't delete %s", addrstr); 3311 WGLOG(LOG_WARNING, "Couldn't delete %s", addrstr);
3280 } 3312 }
3281 } 3313 }
3282 rw_exit(wg->wg_rwlock); 3314 rw_exit(wg->wg_rwlock);
3283 3315
 3316 /* Halt all packet processing and timeouts. */
3284 softint_disestablish(wgp->wgp_si); 3317 softint_disestablish(wgp->wgp_si);
3285 callout_halt(&wgp->wgp_rekey_timer, NULL); 3318 callout_halt(&wgp->wgp_rekey_timer, NULL);
3286 callout_halt(&wgp->wgp_handshake_timeout_timer, NULL); 3319 callout_halt(&wgp->wgp_handshake_timeout_timer, NULL);
3287 callout_halt(&wgp->wgp_session_dtor_timer, NULL); 3320 callout_halt(&wgp->wgp_session_dtor_timer, NULL);
3288 3321
 3322 /* Remove the sessions by index. */
 3323 if ((index = wgp->wgp_session_stable->wgs_sender_index) != 0) {
 3324 thmap_del(wg->wg_sessions_byindex, &index, sizeof index);
 3325 wgp->wgp_session_stable->wgs_sender_index = 0;
 3326 }
 3327 if ((index = wgp->wgp_session_unstable->wgs_sender_index) != 0) {
 3328 thmap_del(wg->wg_sessions_byindex, &index, sizeof index);
 3329 wgp->wgp_session_unstable->wgs_sender_index = 0;
 3330 }
 3331
 3332 /* Wait for all thmap_gets to complete, and GC. */
 3333 garbage = thmap_stage_gc(wg->wg_sessions_byindex);
 3334 mutex_enter(wgp->wgp_lock);
 3335 pserialize_perform(wgp->wgp_psz);
 3336 mutex_exit(wgp->wgp_lock);
 3337 thmap_gc(wg->wg_sessions_byindex, garbage);
 3338
3289 wgs = wgp->wgp_session_unstable; 3339 wgs = wgp->wgp_session_unstable;
3290 psref_target_destroy(&wgs->wgs_psref, wg_psref_class); 3340 psref_target_destroy(&wgs->wgs_psref, wg_psref_class);
3291 mutex_obj_free(wgs->wgs_lock); 3341 mutex_obj_free(wgs->wgs_lock);
3292 mutex_destroy(&wgs->wgs_recvwin->lock); 3342 mutex_destroy(&wgs->wgs_recvwin->lock);
3293 kmem_free(wgs->wgs_recvwin, sizeof(*wgs->wgs_recvwin)); 3343 kmem_free(wgs->wgs_recvwin, sizeof(*wgs->wgs_recvwin));
3294#ifndef __HAVE_ATOMIC64_LOADSTORE 3344#ifndef __HAVE_ATOMIC64_LOADSTORE
3295 mutex_destroy(&wgs->wgs_send_counter_lock); 3345 mutex_destroy(&wgs->wgs_send_counter_lock);
3296#endif 3346#endif
3297 kmem_free(wgs, sizeof(*wgs)); 3347 kmem_free(wgs, sizeof(*wgs));
 3348
3298 wgs = wgp->wgp_session_stable; 3349 wgs = wgp->wgp_session_stable;
3299 psref_target_destroy(&wgs->wgs_psref, wg_psref_class); 3350 psref_target_destroy(&wgs->wgs_psref, wg_psref_class);
3300 mutex_obj_free(wgs->wgs_lock); 3351 mutex_obj_free(wgs->wgs_lock);
3301 mutex_destroy(&wgs->wgs_recvwin->lock); 3352 mutex_destroy(&wgs->wgs_recvwin->lock);
3302 kmem_free(wgs->wgs_recvwin, sizeof(*wgs->wgs_recvwin)); 3353 kmem_free(wgs->wgs_recvwin, sizeof(*wgs->wgs_recvwin));
3303#ifndef __HAVE_ATOMIC64_LOADSTORE 3354#ifndef __HAVE_ATOMIC64_LOADSTORE
3304 mutex_destroy(&wgs->wgs_send_counter_lock); 3355 mutex_destroy(&wgs->wgs_send_counter_lock);
3305#endif 3356#endif
3306 kmem_free(wgs, sizeof(*wgs)); 3357 kmem_free(wgs, sizeof(*wgs));
3307 3358
3308 psref_target_destroy(&wgp->wgp_endpoint->wgsa_psref, wg_psref_class); 3359 psref_target_destroy(&wgp->wgp_endpoint->wgsa_psref, wg_psref_class);
3309 psref_target_destroy(&wgp->wgp_endpoint0->wgsa_psref, wg_psref_class); 3360 psref_target_destroy(&wgp->wgp_endpoint0->wgsa_psref, wg_psref_class);
3310 kmem_free(wgp->wgp_endpoint, sizeof(*wgp->wgp_endpoint)); 3361 kmem_free(wgp->wgp_endpoint, sizeof(*wgp->wgp_endpoint));
3311 kmem_free(wgp->wgp_endpoint0, sizeof(*wgp->wgp_endpoint0)); 3362 kmem_free(wgp->wgp_endpoint0, sizeof(*wgp->wgp_endpoint0));
3312 3363
3313 pserialize_destroy(wgp->wgp_psz); 3364 pserialize_destroy(wgp->wgp_psz);
3314 pcq_destroy(wgp->wgp_q); 3365 pcq_destroy(wgp->wgp_q);
3315 mutex_obj_free(wgp->wgp_lock); 3366 mutex_obj_free(wgp->wgp_lock);
3316 3367
3317 kmem_free(wgp, sizeof(*wgp)); 3368 kmem_free(wgp, sizeof(*wgp));
3318} 3369}
3319 3370
3320static void 3371static void
3321wg_destroy_all_peers(struct wg_softc *wg) 3372wg_destroy_all_peers(struct wg_softc *wg)
3322{ 3373{
3323 struct wg_peer *wgp; 3374 struct wg_peer *wgp, *wgp0 __diagused;
 3375 void *garbage_byname, *garbage_bypubkey;
3324 3376
3325restart: 3377restart:
 3378 garbage_byname = garbage_bypubkey = NULL;
3326 mutex_enter(wg->wg_lock); 3379 mutex_enter(wg->wg_lock);
3327 WG_PEER_WRITER_FOREACH(wgp, wg) { 3380 WG_PEER_WRITER_FOREACH(wgp, wg) {
 3381 if (wgp->wgp_name[0]) {
 3382 wgp0 = thmap_del(wg->wg_peers_byname, wgp->wgp_name,
 3383 strlen(wgp->wgp_name));
 3384 KASSERT(wgp0 == wgp);
 3385 garbage_byname = thmap_stage_gc(wg->wg_peers_byname);
 3386 }
 3387 wgp0 = thmap_del(wg->wg_peers_bypubkey, wgp->wgp_pubkey,
 3388 sizeof(wgp->wgp_pubkey));
 3389 KASSERT(wgp0 == wgp);
 3390 garbage_bypubkey = thmap_stage_gc(wg->wg_peers_bypubkey);
3328 WG_PEER_WRITER_REMOVE(wgp); 3391 WG_PEER_WRITER_REMOVE(wgp);
3329 wg->wg_npeers--; 3392 wg->wg_npeers--;
3330 mutex_enter(wgp->wgp_lock); 3393 mutex_enter(wgp->wgp_lock);
3331 wgp->wgp_state = WGP_STATE_DESTROYING; 3394 wgp->wgp_state = WGP_STATE_DESTROYING;
3332 pserialize_perform(wgp->wgp_psz); 3395 pserialize_perform(wgp->wgp_psz);
3333 mutex_exit(wgp->wgp_lock); 3396 mutex_exit(wgp->wgp_lock);
3334 PSLIST_ENTRY_DESTROY(wgp, wgp_peerlist_entry); 3397 PSLIST_ENTRY_DESTROY(wgp, wgp_peerlist_entry);
3335 break; 3398 break;
3336 } 3399 }
3337 mutex_exit(wg->wg_lock); 3400 mutex_exit(wg->wg_lock);
3338 3401
3339 if (wgp == NULL) 3402 if (wgp == NULL)
3340 return; 3403 return;
3341 3404
3342 psref_target_destroy(&wgp->wgp_psref, wg_psref_class); 3405 psref_target_destroy(&wgp->wgp_psref, wg_psref_class);
3343 3406
3344 wg_destroy_peer(wgp); 3407 wg_destroy_peer(wgp);
 3408 thmap_gc(wg->wg_peers_byname, garbage_byname);
 3409 thmap_gc(wg->wg_peers_bypubkey, garbage_bypubkey);
3345 3410
3346 goto restart; 3411 goto restart;
3347} 3412}
3348 3413
3349static int 3414static int
3350wg_destroy_peer_name(struct wg_softc *wg, const char *name) 3415wg_destroy_peer_name(struct wg_softc *wg, const char *name)
3351{ 3416{
3352 struct wg_peer *wgp; 3417 struct wg_peer *wgp, *wgp0 __diagused;
 3418 void *garbage_byname, *garbage_bypubkey;
3353 3419
3354 mutex_enter(wg->wg_lock); 3420 mutex_enter(wg->wg_lock);
3355 WG_PEER_WRITER_FOREACH(wgp, wg) { 3421 wgp = thmap_del(wg->wg_peers_byname, name, strlen(name));
3356 if (strcmp(wgp->wgp_name, name) == 0) 
3357 break; 
3358 } 
3359 if (wgp != NULL) { 3422 if (wgp != NULL) {
 3423 wgp0 = thmap_del(wg->wg_peers_bypubkey, wgp->wgp_pubkey,
 3424 sizeof(wgp->wgp_pubkey));
 3425 KASSERT(wgp0 == wgp);
 3426 garbage_byname = thmap_stage_gc(wg->wg_peers_byname);
 3427 garbage_bypubkey = thmap_stage_gc(wg->wg_peers_bypubkey);
3360 WG_PEER_WRITER_REMOVE(wgp); 3428 WG_PEER_WRITER_REMOVE(wgp);
3361 wg->wg_npeers--; 3429 wg->wg_npeers--;
3362 mutex_enter(wgp->wgp_lock); 3430 mutex_enter(wgp->wgp_lock);
3363 wgp->wgp_state = WGP_STATE_DESTROYING; 3431 wgp->wgp_state = WGP_STATE_DESTROYING;
3364 pserialize_perform(wgp->wgp_psz); 3432 pserialize_perform(wgp->wgp_psz);
3365 mutex_exit(wgp->wgp_lock); 3433 mutex_exit(wgp->wgp_lock);
3366 PSLIST_ENTRY_DESTROY(wgp, wgp_peerlist_entry); 3434 PSLIST_ENTRY_DESTROY(wgp, wgp_peerlist_entry);
3367 } 3435 }
3368 mutex_exit(wg->wg_lock); 3436 mutex_exit(wg->wg_lock);
3369 3437
3370 if (wgp == NULL) 3438 if (wgp == NULL)
3371 return ENOENT; 3439 return ENOENT;
3372 3440
3373 psref_target_destroy(&wgp->wgp_psref, wg_psref_class); 3441 psref_target_destroy(&wgp->wgp_psref, wg_psref_class);
3374 3442
3375 wg_destroy_peer(wgp); 3443 wg_destroy_peer(wgp);
 3444 thmap_gc(wg->wg_peers_byname, garbage_byname);
 3445 thmap_gc(wg->wg_peers_bypubkey, garbage_bypubkey);
3376 3446
3377 return 0; 3447 return 0;
3378} 3448}
3379 3449
3380static int 3450static int
3381wg_if_attach(struct wg_softc *wg) 3451wg_if_attach(struct wg_softc *wg)
3382{ 3452{
3383 int error; 3453 int error;
3384 3454
3385 wg->wg_if.if_addrlen = 0; 3455 wg->wg_if.if_addrlen = 0;
3386 wg->wg_if.if_mtu = WG_MTU; 3456 wg->wg_if.if_mtu = WG_MTU;
3387 wg->wg_if.if_flags = IFF_MULTICAST; 3457 wg->wg_if.if_flags = IFF_MULTICAST;
3388 wg->wg_if.if_extflags = IFEF_NO_LINK_STATE_CHANGE; 3458 wg->wg_if.if_extflags = IFEF_NO_LINK_STATE_CHANGE;
@@ -3422,39 +3492,45 @@ wg_clone_create(struct if_clone *ifc, in @@ -3422,39 +3492,45 @@ wg_clone_create(struct if_clone *ifc, in
3422 if (error != 0) { 3492 if (error != 0) {
3423 kmem_free(wg, sizeof(struct wg_softc)); 3493 kmem_free(wg, sizeof(struct wg_softc));
3424 return error; 3494 return error;
3425 } 3495 }
3426 3496
3427 rn_inithead((void **)&wg->wg_rtable_ipv4, 3497 rn_inithead((void **)&wg->wg_rtable_ipv4,
3428 offsetof(struct sockaddr_in, sin_addr) * NBBY); 3498 offsetof(struct sockaddr_in, sin_addr) * NBBY);
3429#ifdef INET6 3499#ifdef INET6
3430 rn_inithead((void **)&wg->wg_rtable_ipv6, 3500 rn_inithead((void **)&wg->wg_rtable_ipv6,
3431 offsetof(struct sockaddr_in6, sin6_addr) * NBBY); 3501 offsetof(struct sockaddr_in6, sin6_addr) * NBBY);
3432#endif 3502#endif
3433 3503
3434 PSLIST_INIT(&wg->wg_peers); 3504 PSLIST_INIT(&wg->wg_peers);
 3505 wg->wg_peers_bypubkey = thmap_create(0, NULL, THMAP_NOCOPY);
 3506 wg->wg_peers_byname = thmap_create(0, NULL, THMAP_NOCOPY);
 3507 wg->wg_sessions_byindex = thmap_create(0, NULL, THMAP_NOCOPY);
3435 wg->wg_lock = mutex_obj_alloc(MUTEX_DEFAULT, IPL_NONE); 3508 wg->wg_lock = mutex_obj_alloc(MUTEX_DEFAULT, IPL_NONE);
3436 wg->wg_rwlock = rw_obj_alloc(); 3509 wg->wg_rwlock = rw_obj_alloc();
3437 wg->wg_ops = &wg_ops_rumpkernel; 3510 wg->wg_ops = &wg_ops_rumpkernel;
3438 3511
3439 error = wg_if_attach(wg); 3512 error = wg_if_attach(wg);
3440 if (error != 0) { 3513 if (error != 0) {
3441 wg_worker_destroy(wg); 3514 wg_worker_destroy(wg);
3442 if (wg->wg_rtable_ipv4 != NULL) 3515 if (wg->wg_rtable_ipv4 != NULL)
3443 free(wg->wg_rtable_ipv4, M_RTABLE); 3516 free(wg->wg_rtable_ipv4, M_RTABLE);
3444 if (wg->wg_rtable_ipv6 != NULL) 3517 if (wg->wg_rtable_ipv6 != NULL)
3445 free(wg->wg_rtable_ipv6, M_RTABLE); 3518 free(wg->wg_rtable_ipv6, M_RTABLE);
3446 PSLIST_DESTROY(&wg->wg_peers); 3519 PSLIST_DESTROY(&wg->wg_peers);
3447 mutex_obj_free(wg->wg_lock); 3520 mutex_obj_free(wg->wg_lock);
 3521 thmap_destroy(wg->wg_sessions_byindex);
 3522 thmap_destroy(wg->wg_peers_byname);
 3523 thmap_destroy(wg->wg_peers_bypubkey);
3448 kmem_free(wg, sizeof(struct wg_softc)); 3524 kmem_free(wg, sizeof(struct wg_softc));
3449 return error; 3525 return error;
3450 } 3526 }
3451 3527
3452 mutex_enter(&wg_softcs.lock); 3528 mutex_enter(&wg_softcs.lock);
3453 LIST_INSERT_HEAD(&wg_softcs.list, wg, wg_list); 3529 LIST_INSERT_HEAD(&wg_softcs.list, wg, wg_list);
3454 mutex_exit(&wg_softcs.lock); 3530 mutex_exit(&wg_softcs.lock);
3455 3531
3456 return 0; 3532 return 0;
3457} 3533}
3458 3534
3459static int 3535static int
3460wg_clone_destroy(struct ifnet *ifp) 3536wg_clone_destroy(struct ifnet *ifp)
@@ -3472,26 +3548,29 @@ wg_clone_destroy(struct ifnet *ifp) @@ -3472,26 +3548,29 @@ wg_clone_destroy(struct ifnet *ifp)
3472 } 3548 }
3473#endif 3549#endif
3474 3550
3475 bpf_detach(ifp); 3551 bpf_detach(ifp);
3476 if_detach(ifp); 3552 if_detach(ifp);
3477 wg_worker_destroy(wg); 3553 wg_worker_destroy(wg);
3478 wg_destroy_all_peers(wg); 3554 wg_destroy_all_peers(wg);
3479 if (wg->wg_rtable_ipv4 != NULL) 3555 if (wg->wg_rtable_ipv4 != NULL)
3480 free(wg->wg_rtable_ipv4, M_RTABLE); 3556 free(wg->wg_rtable_ipv4, M_RTABLE);
3481 if (wg->wg_rtable_ipv6 != NULL) 3557 if (wg->wg_rtable_ipv6 != NULL)
3482 free(wg->wg_rtable_ipv6, M_RTABLE); 3558 free(wg->wg_rtable_ipv6, M_RTABLE);
3483 3559
3484 PSLIST_DESTROY(&wg->wg_peers); 3560 PSLIST_DESTROY(&wg->wg_peers);
 3561 thmap_destroy(wg->wg_sessions_byindex);
 3562 thmap_destroy(wg->wg_peers_byname);
 3563 thmap_destroy(wg->wg_peers_bypubkey);
3485 mutex_obj_free(wg->wg_lock); 3564 mutex_obj_free(wg->wg_lock);
3486 rw_obj_free(wg->wg_rwlock); 3565 rw_obj_free(wg->wg_rwlock);
3487 3566
3488 kmem_free(wg, sizeof(struct wg_softc)); 3567 kmem_free(wg, sizeof(struct wg_softc));
3489 3568
3490 return 0; 3569 return 0;
3491} 3570}
3492 3571
3493static struct wg_peer * 3572static struct wg_peer *
3494wg_pick_peer_by_sa(struct wg_softc *wg, const struct sockaddr *sa, 3573wg_pick_peer_by_sa(struct wg_softc *wg, const struct sockaddr *sa,
3495 struct psref *psref) 3574 struct psref *psref)
3496{ 3575{
3497 struct radix_node_head *rnh; 3576 struct radix_node_head *rnh;
@@ -4066,41 +4145,59 @@ wg_ioctl_set_listen_port(struct wg_softc @@ -4066,41 +4145,59 @@ wg_ioctl_set_listen_port(struct wg_softc
4066 error = wg->wg_ops->bind_port(wg, (uint16_t)port); 4145 error = wg->wg_ops->bind_port(wg, (uint16_t)port);
4067 4146
4068out: 4147out:
4069 kmem_free(buf, ifd->ifd_len + 1); 4148 kmem_free(buf, ifd->ifd_len + 1);
4070 return error; 4149 return error;
4071} 4150}
4072 4151
4073static int 4152static int
4074wg_ioctl_add_peer(struct wg_softc *wg, struct ifdrv *ifd) 4153wg_ioctl_add_peer(struct wg_softc *wg, struct ifdrv *ifd)
4075{ 4154{
4076 int error; 4155 int error;
4077 prop_dictionary_t prop_dict; 4156 prop_dictionary_t prop_dict;
4078 char *buf = NULL; 4157 char *buf = NULL;
4079 struct wg_peer *wgp = NULL; 4158 struct wg_peer *wgp = NULL, *wgp0 __diagused;
4080 4159
4081 error = wg_alloc_prop_buf(&buf, ifd); 4160 error = wg_alloc_prop_buf(&buf, ifd);
4082 if (error != 0) 4161 if (error != 0)
4083 return error; 4162 return error;
4084 error = EINVAL; 4163 error = EINVAL;
4085 prop_dict = prop_dictionary_internalize(buf); 4164 prop_dict = prop_dictionary_internalize(buf);
4086 if (prop_dict == NULL) 4165 if (prop_dict == NULL)
4087 goto out; 4166 goto out;
4088 4167
4089 error = wg_handle_prop_peer(wg, prop_dict, &wgp); 4168 error = wg_handle_prop_peer(wg, prop_dict, &wgp);
4090 if (error != 0) 4169 if (error != 0)
4091 goto out; 4170 goto out;
4092 4171
4093 mutex_enter(wg->wg_lock); 4172 mutex_enter(wg->wg_lock);
 4173 if (thmap_get(wg->wg_peers_bypubkey, wgp->wgp_pubkey,
 4174 sizeof(wgp->wgp_pubkey)) != NULL ||
 4175 (wgp->wgp_name[0] &&
 4176 thmap_get(wg->wg_peers_byname, wgp->wgp_name,
 4177 strlen(wgp->wgp_name)) != NULL)) {
 4178 mutex_exit(wg->wg_lock);
 4179 wg_destroy_peer(wgp);
 4180 error = EEXIST;
 4181 goto out;
 4182 }
 4183 wgp0 = thmap_put(wg->wg_peers_bypubkey, wgp->wgp_pubkey,
 4184 sizeof(wgp->wgp_pubkey), wgp);
 4185 KASSERT(wgp0 == wgp);
 4186 if (wgp->wgp_name[0]) {
 4187 wgp0 = thmap_put(wg->wg_peers_byname, wgp->wgp_name,
 4188 strlen(wgp->wgp_name), wgp);
 4189 KASSERT(wgp0 == wgp);
 4190 }
4094 WG_PEER_WRITER_INSERT_HEAD(wgp, wg); 4191 WG_PEER_WRITER_INSERT_HEAD(wgp, wg);
4095 wg->wg_npeers++; 4192 wg->wg_npeers++;
4096 mutex_exit(wg->wg_lock); 4193 mutex_exit(wg->wg_lock);
4097 4194
4098out: 4195out:
4099 kmem_free(buf, ifd->ifd_len + 1); 4196 kmem_free(buf, ifd->ifd_len + 1);
4100 return error; 4197 return error;
4101} 4198}
4102 4199
4103static int 4200static int
4104wg_ioctl_delete_peer(struct wg_softc *wg, struct ifdrv *ifd) 4201wg_ioctl_delete_peer(struct wg_softc *wg, struct ifdrv *ifd)
4105{ 4202{
4106 int error; 4203 int error;