FreeBSD/Linux Kernel Cross Reference
sys/netkey/keysock.c
1 /* $NetBSD: keysock.c,v 1.40 2005/01/23 18:41:57 matt Exp $ */
2 /* $KAME: keysock.c,v 1.32 2003/08/22 05:45:08 itojun Exp $ */
3
4 /*
5 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the project nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33 #include <sys/cdefs.h>
34 __KERNEL_RCSID(0, "$NetBSD: keysock.c,v 1.40 2005/01/23 18:41:57 matt Exp $");
35
36 #include "opt_inet.h"
37
38 /* This code has derived from sys/net/rtsock.c on FreeBSD2.2.5 */
39
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/kernel.h>
43 #include <sys/mbuf.h>
44 #include <sys/socket.h>
45 #include <sys/socketvar.h>
46 #include <sys/domain.h>
47 #include <sys/protosw.h>
48 #include <sys/errno.h>
49 #include <sys/proc.h>
50 #include <sys/queue.h>
51
52 #include <net/raw_cb.h>
53 #include <net/route.h>
54 #include <netinet/in.h>
55
56 #include <net/pfkeyv2.h>
57 #include <netkey/keydb.h>
58 #include <netkey/key.h>
59 #include <netkey/keysock.h>
60 #include <netkey/key_debug.h>
61
62 #include <machine/stdarg.h>
63
64 struct sockaddr key_dst = { 2, PF_KEY, };
65 struct sockaddr key_src = { 2, PF_KEY, };
66
67 struct pfkeystat pfkeystat;
68
69 static int key_receive __P((struct socket *, struct mbuf **, struct uio *,
70 struct mbuf **, struct mbuf **, int *));
71
72 static int key_sendup0 __P((struct rawcb *, struct mbuf *, int, int));
73
74 static int
75 key_receive(struct socket *so, struct mbuf **paddr, struct uio *uio,
76 struct mbuf **mp0, struct mbuf **controlp, int *flagsp)
77 {
78 struct rawcb *rp = sotorawcb(so);
79 struct keycb *kp = (struct keycb *)rp;
80 int error;
81 int s;
82
83 error = (*kp->kp_receive)(so, paddr, uio, mp0, controlp, flagsp);
84
85 /*
86 * now we might have enough receive buffer space.
87 * pull packets from kp_queue as many as possible.
88 */
89 s = splsoftnet();
90 while (/*CONSTCOND*/ 1) {
91 struct mbuf *m;
92
93 m = kp->kp_queue;
94 if (m == NULL || sbspace(&so->so_rcv) < m->m_pkthdr.len)
95 break;
96 kp->kp_queue = m->m_nextpkt;
97 m->m_nextpkt = NULL; /* safety */
98 if (key_sendup0(rp, m, 0, 1))
99 break;
100 }
101 splx(s);
102
103 return error;
104 }
105
106 /*
107 * key_usrreq()
108 * derived from net/rtsock.c:route_usrreq()
109 */
110 int
111 key_usrreq(so, req, m, nam, control, p)
112 struct socket *so;
113 int req;
114 struct mbuf *m, *nam, *control;
115 struct proc *p;
116 {
117 int error = 0;
118 struct keycb *kp = (struct keycb *)sotorawcb(so);
119 int s;
120
121 s = splsoftnet();
122 if (req == PRU_ATTACH) {
123 kp = (struct keycb *)malloc(sizeof(*kp), M_PCB,
124 M_WAITOK|M_ZERO);
125 so->so_pcb = (caddr_t)kp;
126 kp->kp_receive = so->so_receive;
127 so->so_receive = key_receive;
128 }
129 if (req == PRU_DETACH && kp) {
130 int af = kp->kp_raw.rcb_proto.sp_protocol;
131 struct mbuf *n;
132
133 if (af == PF_KEY)
134 key_cb.key_count--;
135 key_cb.any_count--;
136
137 key_freereg(so);
138
139 while (kp->kp_queue) {
140 n = kp->kp_queue->m_nextpkt;
141 kp->kp_queue->m_nextpkt = NULL;
142 m_freem(kp->kp_queue);
143 kp->kp_queue = n;
144 }
145 }
146
147 error = raw_usrreq(so, req, m, nam, control, p);
148 m = control = NULL; /* reclaimed in raw_usrreq */
149 kp = (struct keycb *)sotorawcb(so);
150 if (req == PRU_ATTACH && kp) {
151 int af = kp->kp_raw.rcb_proto.sp_protocol;
152 if (error) {
153 pfkeystat.sockerr++;
154 free((caddr_t)kp, M_PCB);
155 so->so_pcb = (caddr_t) 0;
156 splx(s);
157 return (error);
158 }
159
160 kp->kp_promisc = kp->kp_registered = 0;
161
162 if (af == PF_KEY)
163 key_cb.key_count++;
164 key_cb.any_count++;
165 kp->kp_raw.rcb_laddr = &key_src;
166 kp->kp_raw.rcb_faddr = &key_dst;
167 soisconnected(so);
168 so->so_options |= SO_USELOOPBACK;
169 }
170 splx(s);
171 return (error);
172 }
173
174 /*
175 * key_output()
176 */
177 int
178 key_output(struct mbuf *m, ...)
179 {
180 struct sadb_msg *msg;
181 int len, error = 0;
182 int s;
183 struct socket *so;
184 va_list ap;
185
186 va_start(ap, m);
187 so = va_arg(ap, struct socket *);
188 va_end(ap);
189
190 if (m == 0)
191 panic("key_output: NULL pointer was passed.");
192
193 pfkeystat.out_total++;
194 pfkeystat.out_bytes += m->m_pkthdr.len;
195
196 len = m->m_pkthdr.len;
197 if (len < sizeof(struct sadb_msg)) {
198 pfkeystat.out_tooshort++;
199 error = EINVAL;
200 goto end;
201 }
202
203 if (m->m_len < sizeof(struct sadb_msg)) {
204 if ((m = m_pullup(m, sizeof(struct sadb_msg))) == 0) {
205 pfkeystat.out_nomem++;
206 error = ENOBUFS;
207 goto end;
208 }
209 }
210
211 if ((m->m_flags & M_PKTHDR) == 0)
212 panic("key_output: not M_PKTHDR ??");
213
214 KEYDEBUG(KEYDEBUG_KEY_DUMP, kdebug_mbuf(m));
215
216 msg = mtod(m, struct sadb_msg *);
217 pfkeystat.out_msgtype[msg->sadb_msg_type]++;
218 if (len != PFKEY_UNUNIT64(msg->sadb_msg_len)) {
219 pfkeystat.out_invlen++;
220 error = EINVAL;
221 goto end;
222 }
223
224 /*XXX giant lock*/
225 s = splsoftnet();
226 error = key_parse(m, so);
227 m = NULL;
228 splx(s);
229 end:
230 if (m)
231 m_freem(m);
232 return error;
233 }
234
235 /*
236 * send message to the socket.
237 */
238 static int
239 key_sendup0(rp, m, promisc, canwait)
240 struct rawcb *rp;
241 struct mbuf *m;
242 int promisc;
243 int canwait;
244 {
245 struct keycb *kp = (struct keycb *)rp;
246 struct mbuf *n;
247 int error = 0;
248
249 if (promisc) {
250 struct sadb_msg *pmsg;
251
252 M_PREPEND(m, sizeof(struct sadb_msg), M_NOWAIT);
253 if (m && m->m_len < sizeof(struct sadb_msg))
254 m = m_pullup(m, sizeof(struct sadb_msg));
255 if (!m) {
256 pfkeystat.in_nomem++;
257 return ENOBUFS;
258 }
259 m->m_pkthdr.len += sizeof(*pmsg);
260
261 pmsg = mtod(m, struct sadb_msg *);
262 bzero(pmsg, sizeof(*pmsg));
263 pmsg->sadb_msg_version = PF_KEY_V2;
264 pmsg->sadb_msg_type = SADB_X_PROMISC;
265 pmsg->sadb_msg_len = PFKEY_UNIT64(m->m_pkthdr.len);
266 /* pid and seq? */
267
268 pfkeystat.in_msgtype[pmsg->sadb_msg_type]++;
269 }
270
271 if (canwait) {
272 if (kp->kp_queue) {
273 for (n = kp->kp_queue; n && n->m_nextpkt;
274 n = n->m_nextpkt)
275 ;
276 n->m_nextpkt = m;
277 m = kp->kp_queue;
278 kp->kp_queue = NULL;
279 } else
280 m->m_nextpkt = NULL; /* just for safety */
281 } else
282 m->m_nextpkt = NULL;
283
284 for (; m && error == 0; m = n) {
285 n = m->m_nextpkt;
286
287 if (canwait &&
288 sbspace(&rp->rcb_socket->so_rcv) < m->m_pkthdr.len) {
289 error = EAGAIN;
290 goto recovery;
291 }
292
293 m->m_nextpkt = NULL;
294
295 if (!sbappendaddr(&rp->rcb_socket->so_rcv,
296 (struct sockaddr *)&key_src, m, NULL)) {
297 pfkeystat.in_nomem++;
298 error = ENOBUFS;
299 goto recovery;
300 } else {
301 sorwakeup(rp->rcb_socket);
302 error = 0;
303 }
304 }
305 return (error);
306
307 recovery:
308 if (kp->kp_queue) {
309 /*
310 * kp_queue != NULL implies !canwait.
311 */
312 KASSERT(!canwait);
313 KASSERT(m->m_nextpkt == NULL);
314 /*
315 * insert m to the head of queue, as normally mbuf on the queue
316 * is less important than others.
317 */
318 if (m) {
319 m->m_nextpkt = kp->kp_queue;
320 kp->kp_queue = m;
321 }
322 } else {
323 /* recover the queue */
324 if (!m) {
325 /* first ENOBUFS case */
326 kp->kp_queue = n;
327 } else {
328 kp->kp_queue = m;
329 m->m_nextpkt = n;
330 }
331 }
332 return (error);
333 }
334
335 /* so can be NULL if target != KEY_SENDUP_ONE */
336 int
337 key_sendup_mbuf(so, m, target)
338 struct socket *so;
339 struct mbuf *m;
340 int target;
341 {
342 struct mbuf *n;
343 struct keycb *kp;
344 int sendup;
345 struct rawcb *rp;
346 int error = 0;
347 int canwait;
348
349 if (m == NULL)
350 panic("key_sendup_mbuf: NULL pointer was passed.");
351 if (so == NULL && target == KEY_SENDUP_ONE)
352 panic("key_sendup_mbuf: NULL pointer was passed.");
353
354 canwait = target & KEY_SENDUP_CANWAIT;
355 target &= ~KEY_SENDUP_CANWAIT;
356
357 pfkeystat.in_total++;
358 pfkeystat.in_bytes += m->m_pkthdr.len;
359 if (m->m_len < sizeof(struct sadb_msg)) {
360 m = m_pullup(m, sizeof(struct sadb_msg));
361 if (m == NULL) {
362 pfkeystat.in_nomem++;
363 return ENOBUFS;
364 }
365 }
366 if (m->m_len >= sizeof(struct sadb_msg)) {
367 struct sadb_msg *msg;
368 msg = mtod(m, struct sadb_msg *);
369 pfkeystat.in_msgtype[msg->sadb_msg_type]++;
370 }
371
372 for (rp = rawcb.lh_first; rp; rp = rp->rcb_list.le_next)
373 {
374 if (rp->rcb_proto.sp_family != PF_KEY)
375 continue;
376 if (rp->rcb_proto.sp_protocol &&
377 rp->rcb_proto.sp_protocol != PF_KEY_V2) {
378 continue;
379 }
380
381 kp = (struct keycb *)rp;
382
383 /*
384 * If you are in promiscuous mode, and when you get broadcasted
385 * reply, you'll get two PF_KEY messages.
386 * (based on pf_key@inner.net message on 14 Oct 1998)
387 */
388 if (((struct keycb *)rp)->kp_promisc) {
389 if ((n = m_copy(m, 0, (int)M_COPYALL)) != NULL) {
390 (void)key_sendup0(rp, n, 1, canwait);
391 n = NULL;
392 }
393 }
394
395 /* the exact target will be processed later */
396 if (so && sotorawcb(so) == rp)
397 continue;
398
399 sendup = 0;
400 switch (target) {
401 case KEY_SENDUP_ONE:
402 /* the statement has no effect */
403 if (so && sotorawcb(so) == rp)
404 sendup++;
405 break;
406 case KEY_SENDUP_ALL:
407 sendup++;
408 break;
409 case KEY_SENDUP_REGISTERED:
410 if (kp->kp_registered)
411 sendup++;
412 break;
413 }
414 pfkeystat.in_msgtarget[target]++;
415
416 if (!sendup)
417 continue;
418
419 if ((n = m_copy(m, 0, (int)M_COPYALL)) == NULL) {
420 m_freem(m);
421 pfkeystat.in_nomem++;
422 return ENOBUFS;
423 }
424
425 /*
426 * ignore error even if queue is full. PF_KEY does not
427 * guarantee the delivery of the message.
428 * this is important when target == KEY_SENDUP_ALL.
429 */
430 key_sendup0(rp, n, 0, canwait);
431
432 n = NULL;
433 }
434
435 if (so) {
436 error = key_sendup0(sotorawcb(so), m, 0, canwait);
437 m = NULL;
438 } else {
439 error = 0;
440 m_freem(m);
441 }
442 return error;
443 }
444
445
446 /*
447 * Definitions of protocols supported in the KEY domain.
448 */
449
450 DOMAIN_DEFINE(keydomain);
451
452 const struct protosw keysw[] = {
453 { SOCK_RAW, &keydomain, PF_KEY_V2, PR_ATOMIC|PR_ADDR,
454 0, key_output, raw_ctlinput, 0,
455 key_usrreq,
456 raw_init, 0, 0, 0,
457 NULL,
458 }
459 };
460
461 struct domain keydomain =
462 { PF_KEY, "key", key_init, 0, 0,
463 keysw, &keysw[sizeof(keysw)/sizeof(keysw[0])] };
464
Cache object: f2b2704abccff651b916eafe44dcecf1
|