1 /* $OpenBSD: pfkey.c,v 1.16 2004/11/26 18:02:22 markus Exp $ */
2
3 /*
4 * @(#)COPYRIGHT 1.1 (NRL) 17 January 1995
5 *
6 * NRL grants permission for redistribution and use in source and binary
7 * forms, with or without modification, of the software and documentation
8 * created at NRL provided that the following conditions are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgements:
17 * This product includes software developed by the University of
18 * California, Berkeley and its contributors.
19 * This product includes software developed at the Information
20 * Technology Division, US Naval Research Laboratory.
21 * 4. Neither the name of the NRL nor the names of its contributors
22 * may be used to endorse or promote products derived from this software
23 * without specific prior written permission.
24 *
25 * THE SOFTWARE PROVIDED BY NRL IS PROVIDED BY NRL AND CONTRIBUTORS ``AS
26 * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
27 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
28 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NRL OR
29 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
30 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
31 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
32 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
33 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
34 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
35 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 *
37 * The views and conclusions contained in the software and documentation
38 * are those of the authors and should not be interpreted as representing
39 * official policies, either expressed or implied, of the US Naval
40 * Research Laboratory (NRL).
41 */
42
43 /*
44 * Copyright (c) 1995, 1996, 1997, 1998, 1999 Craig Metz. All rights reserved.
45 *
46 * Redistribution and use in source and binary forms, with or without
47 * modification, are permitted provided that the following conditions
48 * are met:
49 * 1. Redistributions of source code must retain the above copyright
50 * notice, this list of conditions and the following disclaimer.
51 * 2. Redistributions in binary form must reproduce the above copyright
52 * notice, this list of conditions and the following disclaimer in the
53 * documentation and/or other materials provided with the distribution.
54 * 3. Neither the name of the author nor the names of any contributors
55 * may be used to endorse or promote products derived from this software
56 * without specific prior written permission.
57 *
58 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
59 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
60 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
61 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
62 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
63 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
64 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
65 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
66 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
67 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
68 * SUCH DAMAGE.
69 */
70
71 #include <sys/types.h>
72 #include <sys/param.h>
73 #include <sys/systm.h>
74 #include <sys/socket.h>
75 #include <sys/mbuf.h>
76 #include <sys/socketvar.h>
77 #include <net/route.h>
78 #include <netinet/ip_ipsp.h>
79 #include <net/pfkeyv2.h>
80
81 #include <sys/protosw.h>
82 #include <sys/domain.h>
83 #include <net/raw_cb.h>
84
85 #define PFKEY_PROTOCOL_MAX 3
86 static struct pfkey_version *pfkey_versions[PFKEY_PROTOCOL_MAX+1] =
87 { NULL, NULL, NULL, NULL };
88
89 #define PFKEY_MSG_MAXSZ 4096
90
91 struct sockaddr pfkey_addr = { 2, PF_KEY, };
92
93 /* static struct domain pfkey_domain; */
94 static int pfkey_usrreq(struct socket *socket, int req, struct mbuf *mbuf,
95 struct mbuf *nam, struct mbuf *control);
96 static int pfkey_output(struct mbuf *mbuf, struct socket *socket);
97
98 int pfkey_register(struct pfkey_version *version);
99 int pfkey_unregister(struct pfkey_version *version);
100 int pfkey_sendup(struct socket *socket, struct mbuf *packet, int more);
101 void pfkey_init(void);
102 int pfkey_buildprotosw(void);
103
104 int
105 pfkey_register(struct pfkey_version *version)
106 {
107 int rval;
108
109 if ((version->protocol > PFKEY_PROTOCOL_MAX) ||
110 (version->protocol < 0))
111 return (EPROTONOSUPPORT);
112
113 if (pfkey_versions[version->protocol])
114 return (EADDRINUSE);
115
116 pfkey_versions[version->protocol] = version;
117
118 if ((rval = pfkey_buildprotosw()) != 0) {
119 pfkey_versions[version->protocol] = NULL;
120 return (rval);
121 }
122
123 return (0);
124 }
125
126 int
127 pfkey_unregister(struct pfkey_version *version)
128 {
129 int rval;
130
131 if ((rval = pfkey_buildprotosw()) != 0)
132 return (rval);
133
134 pfkey_versions[version->protocol] = NULL;
135 return (0);
136 }
137
138 int
139 pfkey_sendup(struct socket *socket, struct mbuf *packet, int more)
140 {
141 struct mbuf *packet2;
142 int s;
143
144 if (more) {
145 if (!(packet2 = m_copym2(packet, 0, M_COPYALL, M_DONTWAIT)))
146 return (ENOMEM);
147 } else
148 packet2 = packet;
149
150 s = spltdb();
151 if (!sbappendaddr(&socket->so_rcv, &pfkey_addr, packet2, NULL)) {
152 m_freem(packet2);
153 splx(s);
154 return (ENOBUFS);
155 }
156 splx(s);
157
158 sorwakeup(socket);
159 return (0);
160 }
161
162 static int
163 pfkey_output(struct mbuf *mbuf, struct socket *socket)
164 {
165 void *message;
166 int error = 0;
167
168 #ifdef DIAGNOSTIC
169 if (!mbuf || !(mbuf->m_flags & M_PKTHDR)) {
170 error = EINVAL;
171 goto ret;
172 }
173 #endif /* DIAGNOSTIC */
174
175 if (mbuf->m_pkthdr.len > PFKEY_MSG_MAXSZ) {
176 error = EMSGSIZE;
177 goto ret;
178 }
179
180 if (!(message = malloc((unsigned long) mbuf->m_pkthdr.len,
181 M_PFKEY, M_DONTWAIT))) {
182 error = ENOMEM;
183 goto ret;
184 }
185
186 m_copydata(mbuf, 0, mbuf->m_pkthdr.len, message);
187
188 error = pfkey_versions[socket->so_proto->pr_protocol]->send(socket,
189 message, mbuf->m_pkthdr.len);
190
191 ret:
192 if (mbuf)
193 m_freem (mbuf);
194 return (error);
195 }
196
197 static int
198 pfkey_attach(struct socket *socket, struct mbuf *proto)
199 {
200 int rval;
201 int s;
202
203 if (!(socket->so_pcb = malloc(sizeof(struct rawcb),
204 M_PCB, M_DONTWAIT)))
205 return (ENOMEM);
206 bzero(socket->so_pcb, sizeof(struct rawcb));
207
208 s = splnet();
209 rval = raw_usrreq(socket, PRU_ATTACH, NULL, proto, NULL);
210 splx(s);
211 if (rval)
212 goto ret;
213
214 ((struct rawcb *)socket->so_pcb)->rcb_faddr = &pfkey_addr;
215 soisconnected(socket);
216
217 socket->so_options |= SO_USELOOPBACK;
218 if ((rval =
219 pfkey_versions[socket->so_proto->pr_protocol]->create(socket)) != 0)
220 goto ret;
221
222 return (0);
223
224 ret:
225 free(socket->so_pcb, M_PCB);
226 return (rval);
227 }
228
229 static int
230 pfkey_detach(struct socket *socket)
231 {
232 int rval, i, s;
233
234 rval = pfkey_versions[socket->so_proto->pr_protocol]->release(socket);
235 s = splnet();
236 i = raw_usrreq(socket, PRU_DETACH, NULL, NULL, NULL);
237 splx(s);
238
239 if (!rval)
240 rval = i;
241
242 return (rval);
243 }
244
245 static int
246 pfkey_usrreq(struct socket *socket, int req, struct mbuf *mbuf,
247 struct mbuf *nam, struct mbuf *control)
248 {
249 int rval;
250 int s;
251
252 if ((socket->so_proto->pr_protocol > PFKEY_PROTOCOL_MAX) ||
253 (socket->so_proto->pr_protocol < 0) ||
254 !pfkey_versions[socket->so_proto->pr_protocol])
255 return (EPROTONOSUPPORT);
256
257 switch (req) {
258 case PRU_ATTACH:
259 return (pfkey_attach(socket, nam));
260
261 case PRU_DETACH:
262 return (pfkey_detach(socket));
263
264 default:
265 s = splnet();
266 rval = raw_usrreq(socket, req, mbuf, nam, control);
267 splx(s);
268 }
269
270 return (rval);
271 }
272
273 static struct domain pfkey_domain = {
274 PF_KEY,
275 "PF_KEY",
276 NULL, /* init */
277 NULL, /* externalize */
278 NULL, /* dispose */
279 NULL, /* protosw */
280 NULL, /* protoswNPROTOSW */
281 NULL, /* dom_next */
282 rn_inithead, /* dom_rtattach */
283 16, /* rtoffset */
284 sizeof(struct sockaddr_encap) /* maxrtkey */
285 };
286
287 static struct protosw pfkey_protosw_template = {
288 SOCK_RAW,
289 &pfkey_domain,
290 -1, /* protocol */
291 PR_ATOMIC | PR_ADDR,
292 (void *) raw_input,
293 (void *) pfkey_output,
294 (void *) raw_ctlinput,
295 NULL, /* ctloutput */
296 pfkey_usrreq,
297 NULL, /* init */
298 NULL, /* fasttimo */
299 NULL, /* slowtimo */
300 NULL, /* drain */
301 NULL /* sysctl */
302 };
303
304 int
305 pfkey_buildprotosw(void)
306 {
307 struct protosw *protosw, *p;
308 int i, j;
309
310 for (i = j = 0; i <= PFKEY_PROTOCOL_MAX; i++)
311 if (pfkey_versions[i])
312 j++;
313
314 if (j) {
315 if (!(protosw = malloc(j * sizeof(struct protosw),
316 M_PFKEY, M_DONTWAIT)))
317 return (ENOMEM);
318
319 for (i = 0, p = protosw; i <= PFKEY_PROTOCOL_MAX; i++)
320 if (pfkey_versions[i]) {
321 bcopy(&pfkey_protosw_template, p,
322 sizeof(struct protosw));
323 p->pr_protocol = pfkey_versions[i]->protocol;
324 p->pr_sysctl = pfkey_versions[i]->sysctl;
325 p++;
326 }
327
328 if (pfkey_domain.dom_protosw)
329 free(pfkey_domain.dom_protosw, M_PFKEY);
330
331 pfkey_domain.dom_protosw = protosw;
332 pfkey_domain.dom_protoswNPROTOSW = p;
333 } else {
334 if (!(protosw = malloc(sizeof(struct protosw), M_PFKEY,
335 M_DONTWAIT)))
336 return (ENOMEM);
337
338 bcopy(&pfkey_protosw_template, protosw,
339 sizeof(struct protosw));
340
341 if (pfkey_domain.dom_protosw)
342 free(pfkey_domain.dom_protosw, M_PFKEY);
343
344 pfkey_domain.dom_protosw = protosw;
345 pfkey_domain.dom_protoswNPROTOSW = protosw;
346 }
347
348 return (0);
349 }
350
351 void
352 pfkey_init(void)
353 {
354 if (pfkey_buildprotosw() != 0)
355 return;
356
357 pfkey_domain.dom_next = domains;
358 domains = &pfkey_domain;
359 pfkeyv2_init();
360 }