2 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the project nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * $FreeBSD: src/sys/netkey/keysock.c,v 1.1.2.4 2003/01/11 19:10:59 ume Exp $
30 * $KAME: keysock.c,v 1.25 2001/08/13 20:07:41 itojun Exp $
33 #include "opt_ipsec.h"
35 /* This code has derived from sys/net/rtsock.c on FreeBSD2.2.5 */
37 #include <sys/types.h>
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/kernel.h>
41 #include <sys/sysctl.h>
43 #include <sys/malloc.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/socketvar2.h>
51 #include <sys/thread2.h>
52 #include <sys/msgport2.h>
54 #include <net/raw_cb.h>
55 #include <net/route.h>
56 #include <net/netmsg.h>
57 #include <netinet/in.h>
59 #include <net/pfkeyv2.h>
60 #include <net/netmsg2.h>
65 #include "key_debug.h"
67 #include <machine/stdarg.h>
69 struct sockaddr key_dst
= { 2, PF_KEY
, };
70 struct sockaddr key_src
= { 2, PF_KEY
, };
72 static int key_sendup0 (struct rawcb
*, struct mbuf
*, int);
74 struct pfkeystat pfkeystat
;
80 key_output(struct mbuf
*m
, struct socket
*so
, ...)
86 panic("key_output: NULL pointer was passed.");
88 pfkeystat
.out_total
++;
89 pfkeystat
.out_bytes
+= m
->m_pkthdr
.len
;
91 len
= m
->m_pkthdr
.len
;
92 if (len
< sizeof(struct sadb_msg
)) {
93 pfkeystat
.out_tooshort
++;
98 if (m
->m_len
< sizeof(struct sadb_msg
)) {
99 if ((m
= m_pullup(m
, sizeof(struct sadb_msg
))) == NULL
) {
100 pfkeystat
.out_nomem
++;
106 if ((m
->m_flags
& M_PKTHDR
) == 0)
107 panic("key_output: not M_PKTHDR ??");
109 KEYDEBUG(KEYDEBUG_KEY_DUMP
, kdebug_mbuf(m
));
111 msg
= mtod(m
, struct sadb_msg
*);
112 pfkeystat
.out_msgtype
[msg
->sadb_msg_type
]++;
113 if (len
!= PFKEY_UNUNIT64(msg
->sadb_msg_len
)) {
114 pfkeystat
.out_invlen
++;
120 lwkt_gettoken(&key_token
);
121 error
= key_parse(m
, so
);
123 lwkt_reltoken(&key_token
);
131 * send message to the socket.
134 key_sendup0(struct rawcb
*rp
, struct mbuf
*m
, int promisc
)
139 struct sadb_msg
*pmsg
;
141 M_PREPEND(m
, sizeof(struct sadb_msg
), M_NOWAIT
);
142 if (m
&& m
->m_len
< sizeof(struct sadb_msg
))
143 m
= m_pullup(m
, sizeof(struct sadb_msg
));
145 pfkeystat
.in_nomem
++;
149 m
->m_pkthdr
.len
+= sizeof(*pmsg
);
151 pmsg
= mtod(m
, struct sadb_msg
*);
152 bzero(pmsg
, sizeof(*pmsg
));
153 pmsg
->sadb_msg_version
= PF_KEY_V2
;
154 pmsg
->sadb_msg_type
= SADB_X_PROMISC
;
155 pmsg
->sadb_msg_len
= PFKEY_UNIT64(m
->m_pkthdr
.len
);
158 pfkeystat
.in_msgtype
[pmsg
->sadb_msg_type
]++;
161 lwkt_gettoken(&key_token
);
162 if (!ssb_appendaddr(&rp
->rcb_socket
->so_rcv
, &key_src
, m
, NULL
)) {
163 pfkeystat
.in_nomem
++;
169 lwkt_reltoken(&key_token
);
170 sorwakeup(rp
->rcb_socket
);
175 * XXX this interface should be obsoleted.
178 * target: target of the resulting message
181 key_sendup(struct socket
*so
, struct sadb_msg
*msg
, u_int len
,
184 struct mbuf
*m
, *n
, *mprev
;
188 if (so
== NULL
|| msg
== NULL
)
189 panic("key_sendup: NULL pointer was passed.");
191 KEYDEBUG(KEYDEBUG_KEY_DUMP
,
192 kprintf("key_sendup: \n");
196 * we increment statistics here, just in case we have ENOBUFS
199 pfkeystat
.in_total
++;
200 pfkeystat
.in_bytes
+= len
;
201 pfkeystat
.in_msgtype
[msg
->sadb_msg_type
]++;
204 * Get mbuf chain whenever possible (not clusters),
205 * to save socket buffer. We'll be generating many SADB_ACQUIRE
206 * messages to listening key sockets. If we simply allocate clusters,
207 * ssb_appendaddr() will raise ENOBUFS due to too little ssb_space().
208 * ssb_space() computes # of actual data bytes AND mbuf region.
210 * TODO: SADB_ACQUIRE filters should be implemented.
216 MGETHDR(n
, M_NOWAIT
, MT_DATA
);
219 MGET(n
, M_NOWAIT
, MT_DATA
);
223 pfkeystat
.in_nomem
++;
226 if (tlen
>= MCLBYTES
) { /*XXX better threshold? */
228 if ((n
->m_flags
& M_EXT
) == 0) {
231 pfkeystat
.in_nomem
++;
249 m
->m_pkthdr
.len
= len
;
250 m
->m_pkthdr
.rcvif
= NULL
;
251 m_copyback(m
, 0, len
, (caddr_t
)msg
);
253 /* avoid duplicated statistics */
254 pfkeystat
.in_total
--;
255 pfkeystat
.in_bytes
-= len
;
256 pfkeystat
.in_msgtype
[msg
->sadb_msg_type
]--;
258 return key_sendup_mbuf(so
, m
, target
);
261 /* so can be NULL if target != KEY_SENDUP_ONE */
263 key_sendup_mbuf(struct socket
*so
, struct mbuf
*m
, int target
)
272 panic("key_sendup_mbuf: NULL pointer was passed.");
273 if (so
== NULL
&& target
== KEY_SENDUP_ONE
)
274 panic("key_sendup_mbuf: NULL pointer was passed.");
276 pfkeystat
.in_total
++;
277 pfkeystat
.in_bytes
+= m
->m_pkthdr
.len
;
278 if (m
->m_len
< sizeof(struct sadb_msg
)) {
280 m
= m_pullup(m
, sizeof(struct sadb_msg
));
282 pfkeystat
.in_nomem
++;
286 /* don't bother pulling it up just for stats */
289 if (m
->m_len
>= sizeof(struct sadb_msg
)) {
290 struct sadb_msg
*msg
;
291 msg
= mtod(m
, struct sadb_msg
*);
292 pfkeystat
.in_msgtype
[msg
->sadb_msg_type
]++;
295 lwkt_gettoken(&key_token
);
297 LIST_FOREACH(rp
, &rawcb_list
, list
)
299 if (rp
->rcb_proto
.sp_family
!= PF_KEY
)
301 if (rp
->rcb_proto
.sp_protocol
302 && rp
->rcb_proto
.sp_protocol
!= PF_KEY_V2
) {
306 kp
= (struct keycb
*)rp
;
309 * If you are in promiscuous mode, and when you get broadcasted
310 * reply, you'll get two PF_KEY messages.
311 * (based on pf_key@inner.net message on 14 Oct 1998)
313 if (((struct keycb
*)rp
)->kp_promisc
) {
314 if ((n
= m_copy(m
, 0, (int)M_COPYALL
)) != NULL
) {
315 key_sendup0(rp
, n
, 1);
320 /* the exact target will be processed later */
321 if (so
&& sotorawcb(so
) == rp
)
327 /* the statement has no effect */
328 if (so
&& sotorawcb(so
) == rp
)
334 case KEY_SENDUP_REGISTERED
:
335 if (kp
->kp_registered
)
339 pfkeystat
.in_msgtarget
[target
]++;
344 if ((n
= m_copy(m
, 0, (int)M_COPYALL
)) == NULL
) {
346 pfkeystat
.in_nomem
++;
347 lwkt_reltoken(&key_token
);
351 if ((error
= key_sendup0(rp
, n
, 0)) != 0) {
352 lwkt_reltoken(&key_token
);
359 lwkt_reltoken(&key_token
);
362 error
= key_sendup0(sotorawcb(so
), m
, 0);
373 * derived from net/rtsock.c:rts_abort()
376 key_abort(netmsg_t msg
)
378 lwkt_gettoken(&key_token
);
380 raw_usrreqs
.pru_abort(msg
);
381 /* msg invalid now */
383 lwkt_reltoken(&key_token
);
388 * derived from net/rtsock.c:rts_attach()
391 key_attach(netmsg_t msg
)
393 struct socket
*so
= msg
->attach
.base
.nm_so
;
394 int proto
= msg
->attach
.nm_proto
;
395 struct pru_attach_info
*ai
= msg
->attach
.nm_ai
;
397 struct netmsg_pru_attach smsg
;
400 if (sotorawcb(so
) != NULL
) {
401 error
= EISCONN
; /* XXX panic? */
406 kp
= kmalloc(sizeof *kp
, M_PCB
, M_WAITOK
| M_ZERO
);
409 * The critical section is necessary to block protocols from sending
410 * error notifications (like RTM_REDIRECT or RTM_LOSING) while
411 * this PCB is extant but incompletely initialized.
412 * Probably we should try to do more of this work beforehand and
413 * eliminate the critical section.
415 lwkt_gettoken(&key_token
);
416 so
->so_pcb
= (caddr_t
)kp
;
417 soreference(so
); /* so_pcb assignment */
419 netmsg_init(&smsg
.base
, so
, &netisr_adone_rport
, 0,
420 raw_usrreqs
.pru_attach
);
421 smsg
.base
.lmsg
.ms_flags
&= ~(MSGF_REPLY
| MSGF_DONE
);
422 smsg
.base
.lmsg
.ms_flags
|= MSGF_SYNC
;
423 smsg
.nm_proto
= proto
;
425 raw_usrreqs
.pru_attach((netmsg_t
)&smsg
);
426 error
= smsg
.base
.lmsg
.ms_error
;
428 kp
= (struct keycb
*)sotorawcb(so
);
431 atomic_add_int(&so
->so_refs
, -1);
432 so
->so_pcb
= (caddr_t
) 0;
433 lwkt_reltoken(&key_token
);
437 kp
->kp_promisc
= kp
->kp_registered
= 0;
439 if (kp
->kp_raw
.rcb_proto
.sp_protocol
== PF_KEY
) /* XXX: AF_KEY */
442 kp
->kp_raw
.rcb_laddr
= &key_src
;
443 kp
->kp_raw
.rcb_faddr
= &key_dst
;
445 so
->so_options
|= SO_USELOOPBACK
;
447 lwkt_reltoken(&key_token
);
450 lwkt_replymsg(&msg
->attach
.base
.lmsg
, error
);
455 * derived from net/rtsock.c:rts_bind()
458 key_bind(netmsg_t msg
)
460 lwkt_gettoken(&key_token
);
462 raw_usrreqs
.pru_bind(msg
); /* xxx just EINVAL */
463 /* msg invalid now */
465 lwkt_reltoken(&key_token
);
470 * derived from net/rtsock.c:rts_connect()
473 key_connect(netmsg_t msg
)
475 lwkt_gettoken(&key_token
);
477 raw_usrreqs
.pru_connect(msg
); /* XXX just EINVAL */
478 /* msg invalid now */
480 lwkt_reltoken(&key_token
);
485 * derived from net/rtsock.c:rts_detach()
488 key_detach(netmsg_t msg
)
490 struct socket
*so
= msg
->detach
.base
.nm_so
;
491 struct keycb
*kp
= (struct keycb
*)sotorawcb(so
);
493 lwkt_gettoken(&key_token
);
496 if (kp
->kp_raw
.rcb_proto
.sp_protocol
== PF_KEY
) {
504 raw_usrreqs
.pru_detach(msg
);
505 /* msg invalid now */
507 lwkt_reltoken(&key_token
);
512 * derived from net/rtsock.c:key_disconnect()
515 key_disconnect(netmsg_t msg
)
517 lwkt_gettoken(&key_token
);
519 raw_usrreqs
.pru_disconnect(msg
);
520 /* msg invalid now */
522 lwkt_reltoken(&key_token
);
527 * derived from net/rtsock.c:rts_peeraddr()
530 key_peeraddr(netmsg_t msg
)
532 lwkt_gettoken(&key_token
);
534 raw_usrreqs
.pru_peeraddr(msg
);
535 /* msg invalid now */
537 lwkt_reltoken(&key_token
);
542 * derived from net/rtsock.c:rts_send()
545 key_send(netmsg_t msg
)
547 lwkt_gettoken(&key_token
);
549 raw_usrreqs
.pru_send(msg
);
550 /* msg invalid now */
552 lwkt_reltoken(&key_token
);
557 * derived from net/rtsock.c:rts_shutdown()
560 key_shutdown(netmsg_t msg
)
562 lwkt_gettoken(&key_token
);
564 raw_usrreqs
.pru_shutdown(msg
);
565 /* msg invalid now */
567 lwkt_reltoken(&key_token
);
572 * derived from net/rtsock.c:rts_sockaddr()
575 key_sockaddr(netmsg_t msg
)
577 lwkt_gettoken(&key_token
);
579 raw_usrreqs
.pru_sockaddr(msg
);
580 /* msg invalid now */
582 lwkt_reltoken(&key_token
);
585 struct pr_usrreqs key_usrreqs
= {
586 .pru_abort
= key_abort
,
587 .pru_accept
= pr_generic_notsupp
,
588 .pru_attach
= key_attach
,
589 .pru_bind
= key_bind
,
590 .pru_connect
= key_connect
,
591 .pru_connect2
= pr_generic_notsupp
,
592 .pru_control
= pr_generic_notsupp
,
593 .pru_detach
= key_detach
,
594 .pru_disconnect
= key_disconnect
,
595 .pru_listen
= pr_generic_notsupp
,
596 .pru_peeraddr
= key_peeraddr
,
597 .pru_rcvd
= pr_generic_notsupp
,
598 .pru_rcvoob
= pr_generic_notsupp
,
599 .pru_send
= key_send
,
600 .pru_sense
= pru_sense_null
,
601 .pru_shutdown
= key_shutdown
,
602 .pru_sockaddr
= key_sockaddr
,
603 .pru_sosend
= sosend
,
604 .pru_soreceive
= soreceive
608 SYSCTL_NODE(_net
, PF_KEY
, key
, CTLFLAG_RW
, 0, "Key Family");
611 * Definitions of protocols supported in the KEY domain.
614 extern struct domain keydomain
;
616 struct protosw keysw
[] = {
619 .pr_domain
= &keydomain
,
620 .pr_protocol
= PF_KEY_V2
,
621 .pr_flags
= PR_ATOMIC
|PR_ADDR
,
624 .pr_output
= key_output
,
625 .pr_ctlinput
= raw_ctlinput
,
626 .pr_ctloutput
= NULL
,
628 .pr_ctlport
= cpu0_ctlport
,
630 .pr_usrreqs
= &key_usrreqs
634 struct domain keydomain
= {
635 PF_KEY
, "key", key_init
, NULL
, NULL
,
636 keysw
, &keysw
[NELEM(keysw
)],