1/*	$KAME: keysock.c,v 1.25 2001/08/13 20:07:41 itojun Exp $	*/
2
3/*-
4 * SPDX-License-Identifier: BSD-3-Clause
5 *
6 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the project nor the names of its contributors
18 *    may be used to endorse or promote products derived from this software
19 *    without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#include "opt_ipsec.h"
35
36/* This code has derived from sys/net/rtsock.c on FreeBSD2.2.5 */
37
38#include <sys/types.h>
39#include <sys/param.h>
40#include <sys/domain.h>
41#include <sys/errno.h>
42#include <sys/kernel.h>
43#include <sys/lock.h>
44#include <sys/malloc.h>
45#include <sys/mbuf.h>
46#include <sys/mutex.h>
47#include <sys/priv.h>
48#include <sys/protosw.h>
49#include <sys/signalvar.h>
50#include <sys/socket.h>
51#include <sys/socketvar.h>
52#include <sys/sysctl.h>
53#include <sys/systm.h>
54
55#include <net/if.h>
56#include <net/vnet.h>
57
58#include <netinet/in.h>
59
60#include <net/pfkeyv2.h>
61#include <netipsec/key.h>
62#include <netipsec/keysock.h>
63#include <netipsec/key_debug.h>
64#include <netipsec/ipsec.h>
65
66#include <machine/stdarg.h>
67
68static struct mtx keysock_mtx;
69MTX_SYSINIT(keysock, &keysock_mtx, "key socket pcb list", MTX_DEF);
70
71#define	KEYSOCK_LOCK()		mtx_lock(&keysock_mtx)
72#define	KEYSOCK_UNLOCK()	mtx_unlock(&keysock_mtx)
73
74VNET_DEFINE_STATIC(LIST_HEAD(, keycb), keycb_list) =
75    LIST_HEAD_INITIALIZER(keycb_list);
76#define	V_keycb_list		VNET(keycb_list)
77
78static struct sockaddr key_src = { 2, PF_KEY, };
79
80static int key_sendup0(struct keycb *, struct mbuf *, int);
81
82VNET_PCPUSTAT_DEFINE(struct pfkeystat, pfkeystat);
83VNET_PCPUSTAT_SYSINIT(pfkeystat);
84
85#ifdef VIMAGE
86VNET_PCPUSTAT_SYSUNINIT(pfkeystat);
87#endif /* VIMAGE */
88
89static int
90key_send(struct socket *so, int flags, struct mbuf *m,
91    struct sockaddr *nam, struct mbuf *control, struct thread *td)
92{
93	struct sadb_msg *msg;
94	int len, error = 0;
95
96	if ((flags & PRUS_OOB) || control != NULL) {
97		m_freem(m);
98		if (control != NULL)
99			m_freem(control);
100		return (EOPNOTSUPP);
101	}
102
103	PFKEYSTAT_INC(out_total);
104	PFKEYSTAT_ADD(out_bytes, m->m_pkthdr.len);
105
106	len = m->m_pkthdr.len;
107	if (len < sizeof(struct sadb_msg)) {
108		PFKEYSTAT_INC(out_tooshort);
109		error = EINVAL;
110		goto end;
111	}
112
113	if (m->m_len < sizeof(struct sadb_msg)) {
114		if ((m = m_pullup(m, sizeof(struct sadb_msg))) == NULL) {
115			PFKEYSTAT_INC(out_nomem);
116			error = ENOBUFS;
117			goto end;
118		}
119	}
120
121	M_ASSERTPKTHDR(m);
122
123	KEYDBG(KEY_DUMP, kdebug_mbuf(m));
124
125	msg = mtod(m, struct sadb_msg *);
126	PFKEYSTAT_INC(out_msgtype[msg->sadb_msg_type]);
127	if (len != PFKEY_UNUNIT64(msg->sadb_msg_len)) {
128		PFKEYSTAT_INC(out_invlen);
129		error = EINVAL;
130		goto end;
131	}
132
133	error = key_parse(m, so);
134	m = NULL;
135end:
136	if (m != NULL)
137		m_freem(m);
138	return (error);
139}
140
141/*
142 * send message to the socket.
143 */
144static int
145key_sendup0(struct keycb *kp, struct mbuf *m, int promisc)
146{
147
148	if (promisc) {
149		struct sadb_msg *pmsg;
150
151		M_PREPEND(m, sizeof(struct sadb_msg), M_NOWAIT);
152		if (m == NULL) {
153			PFKEYSTAT_INC(in_nomem);
154			return (ENOBUFS);
155		}
156		pmsg = mtod(m, struct sadb_msg *);
157		bzero(pmsg, sizeof(*pmsg));
158		pmsg->sadb_msg_version = PF_KEY_V2;
159		pmsg->sadb_msg_type = SADB_X_PROMISC;
160		pmsg->sadb_msg_len = PFKEY_UNIT64(m->m_pkthdr.len);
161		/* pid and seq? */
162
163		PFKEYSTAT_INC(in_msgtype[pmsg->sadb_msg_type]);
164	}
165
166	if (!sbappendaddr(&kp->kp_socket->so_rcv, &key_src, m, NULL)) {
167		PFKEYSTAT_INC(in_nomem);
168		m_freem(m);
169		soroverflow(kp->kp_socket);
170		return (ENOBUFS);
171	}
172
173	sorwakeup(kp->kp_socket);
174	return (0);
175}
176
177/* so can be NULL if target != KEY_SENDUP_ONE */
178int
179key_sendup_mbuf(struct socket *so, struct mbuf *m, int target)
180{
181	struct mbuf *n;
182	struct keycb *kp;
183	int error = 0;
184
185	KASSERT(m != NULL, ("NULL mbuf pointer was passed."));
186	KASSERT(so != NULL || target != KEY_SENDUP_ONE,
187	    ("NULL socket pointer was passed."));
188	KASSERT(target == KEY_SENDUP_ONE || target == KEY_SENDUP_ALL ||
189	    target == KEY_SENDUP_REGISTERED, ("Wrong target %d", target));
190
191	PFKEYSTAT_INC(in_total);
192	PFKEYSTAT_ADD(in_bytes, m->m_pkthdr.len);
193	if (m->m_len < sizeof(struct sadb_msg)) {
194		m = m_pullup(m, sizeof(struct sadb_msg));
195		if (m == NULL) {
196			PFKEYSTAT_INC(in_nomem);
197			return (ENOBUFS);
198		}
199	}
200	if (m->m_len >= sizeof(struct sadb_msg)) {
201		struct sadb_msg *msg;
202		msg = mtod(m, struct sadb_msg *);
203		PFKEYSTAT_INC(in_msgtype[msg->sadb_msg_type]);
204	}
205	KEYSOCK_LOCK();
206	LIST_FOREACH(kp, &V_keycb_list, kp_next) {
207		/*
208		 * If you are in promiscuous mode, and when you get broadcasted
209		 * reply, you'll get two PF_KEY messages.
210		 * (based on pf_key@inner.net message on 14 Oct 1998)
211		 */
212		if (kp->kp_promisc) {
213			n = m_copym(m, 0, M_COPYALL, M_NOWAIT);
214			if (n != NULL)
215				key_sendup0(kp, n, 1);
216			else
217				PFKEYSTAT_INC(in_nomem);
218		}
219
220		/* the exact target will be processed later */
221		if (so != NULL && so->so_pcb == kp)
222			continue;
223
224		if (target == KEY_SENDUP_ONE || (target ==
225		    KEY_SENDUP_REGISTERED && kp->kp_registered == 0))
226			continue;
227
228		/* KEY_SENDUP_ALL + KEY_SENDUP_REGISTERED */
229		n = m_copym(m, 0, M_COPYALL, M_NOWAIT);
230		if (n == NULL) {
231			PFKEYSTAT_INC(in_nomem);
232			/* Try send to another socket */
233			continue;
234		}
235
236		if (key_sendup0(kp, n, 0) == 0)
237			PFKEYSTAT_INC(in_msgtarget[target]);
238	}
239
240	if (so)	{ /* KEY_SENDUP_ONE */
241		error = key_sendup0(so->so_pcb, m, 0);
242		if (error == 0)
243			PFKEYSTAT_INC(in_msgtarget[KEY_SENDUP_ONE]);
244	} else {
245		error = 0;
246		m_freem(m);
247	}
248	KEYSOCK_UNLOCK();
249	return (error);
250}
251
252static u_long key_sendspace = 8192;
253SYSCTL_ULONG(_net_key, OID_AUTO, sendspace, CTLFLAG_RW, &key_sendspace, 0,
254    "Default key socket send space");
255static u_long key_recvspace = 8192;
256SYSCTL_ULONG(_net_key, OID_AUTO, recvspace, CTLFLAG_RW, &key_recvspace, 0,
257    "Default key socket receive space");
258
259static int
260key_attach(struct socket *so, int proto, struct thread *td)
261{
262	struct keycb *kp;
263	int error;
264
265	KASSERT(so->so_pcb == NULL, ("key_attach: so_pcb != NULL"));
266
267	if (td != NULL) {
268		error = priv_check(td, PRIV_NET_RAW);
269		if (error != 0)
270			return (error);
271	}
272
273	error = soreserve(so, key_sendspace, key_recvspace);
274	if (error != 0)
275		return (error);
276
277	kp = malloc(sizeof(*kp), M_PCB, M_WAITOK);
278	kp->kp_socket = so;
279	kp->kp_promisc = kp->kp_registered = 0;
280
281	so->so_pcb = kp;
282	so->so_options |= SO_USELOOPBACK;
283
284	KEYSOCK_LOCK();
285	LIST_INSERT_HEAD(&V_keycb_list, kp, kp_next);
286	KEYSOCK_UNLOCK();
287	soisconnected(so);
288
289	return (0);
290}
291
292static void
293key_close(struct socket *so)
294{
295
296	soisdisconnected(so);
297}
298
299static void
300key_detach(struct socket *so)
301{
302	struct keycb *kp = so->so_pcb;
303
304	key_freereg(so);
305	KEYSOCK_LOCK();
306	LIST_REMOVE(kp, kp_next);
307	KEYSOCK_UNLOCK();
308	free(kp, M_PCB);
309	so->so_pcb = NULL;
310}
311
312static int
313key_shutdown(struct socket *so, enum shutdown_how how)
314{
315	/*
316	 * Note: key socket marks itself as connected through its lifetime.
317	 */
318	switch (how) {
319	case SHUT_RD:
320		socantrcvmore(so);
321		sbrelease(so, SO_RCV);
322		break;
323	case SHUT_RDWR:
324		socantrcvmore(so);
325		sbrelease(so, SO_RCV);
326		/* FALLTHROUGH */
327	case SHUT_WR:
328		socantsendmore(so);
329	}
330
331	return (0);
332}
333
334SYSCTL_NODE(_net, PF_KEY, key, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
335    "Key Family");
336
337static struct protosw keysw = {
338	.pr_type =		SOCK_RAW,
339	.pr_protocol =		PF_KEY_V2,
340	.pr_flags =		PR_ATOMIC | PR_ADDR,
341	.pr_abort =		key_close,
342	.pr_attach =		key_attach,
343	.pr_detach =		key_detach,
344	.pr_send =		key_send,
345	.pr_shutdown =		key_shutdown,
346	.pr_close =		key_close,
347};
348
349static struct domain keydomain = {
350	.dom_family =		PF_KEY,
351	.dom_name =		"key",
352	.dom_nprotosw =		1,
353	.dom_protosw =		{ &keysw },
354};
355DOMAIN_SET(key);
356