1 /* $NetBSD: uipc_domain.c,v 1.84 2009/09/11 22:06:29 dyoung Exp $ */
4 * Copyright (c) 1982, 1986, 1993
5 * The Regents of the University of California. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * @(#)uipc_domain.c 8.3 (Berkeley) 2/14/95
34 #include <sys/cdefs.h>
35 __KERNEL_RCSID(0, "$NetBSD: uipc_domain.c,v 1.84 2009/09/11 22:06:29 dyoung Exp $");
37 #include <sys/param.h>
38 #include <sys/socket.h>
39 #include <sys/socketvar.h>
40 #include <sys/protosw.h>
41 #include <sys/domain.h>
44 #include <sys/kernel.h>
45 #include <sys/systm.h>
46 #include <sys/callout.h>
47 #include <sys/queue.h>
49 #include <sys/sysctl.h>
51 #include <sys/unpcb.h>
53 #include <sys/filedesc.h>
54 #include <sys/kauth.h>
56 MALLOC_DECLARE(M_SOCKADDR
);
58 MALLOC_DEFINE(M_SOCKADDR
, "sockaddr", "socket endpoints");
60 void pffasttimo(void *);
61 void pfslowtimo(void *);
63 struct domainhead domains
= STAILQ_HEAD_INITIALIZER(domains
);
64 static struct domain
*domain_array
[AF_MAX
];
66 callout_t pffasttimo_ch
, pfslowtimo_ch
;
69 * Current time values for fast and slow timeouts. We can use u_int
70 * relatively safely. The fast timer will roll over in 27 years and
71 * the slow timer in 68 years.
76 static struct sysctllog
*domain_sysctllog
;
77 static void sysctl_net_setup(void);
80 domaininit(bool addroute
)
82 __link_set_decl(domains
, struct domain
);
83 struct domain
* const * dpp
;
84 struct domain
*rt_domain
= NULL
;
89 * Add all of the domains. Make sure the PF_ROUTE
90 * domain is added last.
92 __link_set_foreach(dpp
, domains
) {
93 if ((*dpp
)->dom_family
== PF_ROUTE
)
98 if (rt_domain
&& addroute
)
99 domain_attach(rt_domain
);
101 callout_init(&pffasttimo_ch
, CALLOUT_MPSAFE
);
102 callout_init(&pfslowtimo_ch
, CALLOUT_MPSAFE
);
104 callout_reset(&pffasttimo_ch
, 1, pffasttimo
, NULL
);
105 callout_reset(&pfslowtimo_ch
, 1, pfslowtimo
, NULL
);
109 domain_attach(struct domain
*dp
)
111 const struct protosw
*pr
;
113 STAILQ_INSERT_TAIL(&domains
, dp
, dom_link
);
114 if (dp
->dom_family
< __arraycount(domain_array
))
115 domain_array
[dp
->dom_family
] = dp
;
121 if (dp
->dom_mowner
.mo_name
[0] == '\0') {
122 strncpy(dp
->dom_mowner
.mo_name
, dp
->dom_name
,
123 sizeof(dp
->dom_mowner
.mo_name
));
124 MOWNER_ATTACH(&dp
->dom_mowner
);
127 for (pr
= dp
->dom_protosw
; pr
< dp
->dom_protoswNPROTOSW
; pr
++) {
132 if (max_linkhdr
< 16) /* XXX */
134 max_hdr
= max_linkhdr
+ max_protohdr
;
135 max_datalen
= MHLEN
- max_hdr
;
139 pffinddomain(int family
)
143 if (family
< __arraycount(domain_array
) && domain_array
[family
] != NULL
)
144 return domain_array
[family
];
147 if (dp
->dom_family
== family
)
152 const struct protosw
*
153 pffindtype(int family
, int type
)
156 const struct protosw
*pr
;
158 dp
= pffinddomain(family
);
162 for (pr
= dp
->dom_protosw
; pr
< dp
->dom_protoswNPROTOSW
; pr
++)
163 if (pr
->pr_type
&& pr
->pr_type
== type
)
169 const struct protosw
*
170 pffindproto(int family
, int protocol
, int type
)
173 const struct protosw
*pr
;
174 const struct protosw
*maybe
= NULL
;
179 dp
= pffinddomain(family
);
183 for (pr
= dp
->dom_protosw
; pr
< dp
->dom_protoswNPROTOSW
; pr
++) {
184 if ((pr
->pr_protocol
== protocol
) && (pr
->pr_type
== type
))
187 if (type
== SOCK_RAW
&& pr
->pr_type
== SOCK_RAW
&&
188 pr
->pr_protocol
== 0 && maybe
== NULL
)
195 sockaddr_addr(struct sockaddr
*sa
, socklen_t
*slenp
)
197 const struct domain
*dom
;
199 if ((dom
= pffinddomain(sa
->sa_family
)) == NULL
||
200 dom
->dom_sockaddr_addr
== NULL
)
203 return (*dom
->dom_sockaddr_addr
)(sa
, slenp
);
207 sockaddr_const_addr(const struct sockaddr
*sa
, socklen_t
*slenp
)
209 const struct domain
*dom
;
211 if ((dom
= pffinddomain(sa
->sa_family
)) == NULL
||
212 dom
->dom_sockaddr_const_addr
== NULL
)
215 return (*dom
->dom_sockaddr_const_addr
)(sa
, slenp
);
218 const struct sockaddr
*
219 sockaddr_any_by_family(int family
)
221 const struct domain
*dom
;
223 if ((dom
= pffinddomain(family
)) == NULL
)
226 return dom
->dom_sa_any
;
229 const struct sockaddr
*
230 sockaddr_any(const struct sockaddr
*sa
)
232 return sockaddr_any_by_family(sa
->sa_family
);
236 sockaddr_anyaddr(const struct sockaddr
*sa
, socklen_t
*slenp
)
238 const struct sockaddr
*any
;
240 if ((any
= sockaddr_any(sa
)) == NULL
)
243 return sockaddr_const_addr(any
, slenp
);
247 sockaddr_alloc(sa_family_t af
, socklen_t socklen
, int flags
)
250 socklen_t reallen
= MAX(socklen
, offsetof(struct sockaddr
, sa_data
[0]));
252 if ((sa
= malloc(reallen
, M_SOCKADDR
, flags
)) == NULL
)
256 sa
->sa_len
= reallen
;
261 sockaddr_copy(struct sockaddr
*dst
, socklen_t socklen
,
262 const struct sockaddr
*src
)
264 if (__predict_false(socklen
< src
->sa_len
)) {
265 panic("%s: source too long, %d < %d bytes", __func__
, socklen
,
268 return memcpy(dst
, src
, src
->sa_len
);
272 sockaddr_externalize(struct sockaddr
*dst
, socklen_t socklen
,
273 const struct sockaddr
*src
)
277 dom
= pffinddomain(src
->sa_family
);
279 if (dom
!= NULL
&& dom
->dom_sockaddr_externalize
!= NULL
)
280 return (*dom
->dom_sockaddr_externalize
)(dst
, socklen
, src
);
282 return sockaddr_copy(dst
, socklen
, src
);
286 sockaddr_cmp(const struct sockaddr
*sa1
, const struct sockaddr
*sa2
)
291 if (sa1
->sa_family
!= sa2
->sa_family
)
292 return sa1
->sa_family
- sa2
->sa_family
;
294 dom
= pffinddomain(sa1
->sa_family
);
296 if (dom
!= NULL
&& dom
->dom_sockaddr_cmp
!= NULL
)
297 return (*dom
->dom_sockaddr_cmp
)(sa1
, sa2
);
299 len
= MIN(sa1
->sa_len
, sa2
->sa_len
);
301 if (dom
== NULL
|| dom
->dom_sa_cmplen
== 0) {
302 if ((rc
= memcmp(sa1
, sa2
, len
)) != 0)
304 return sa1
->sa_len
- sa2
->sa_len
;
307 if ((rc
= memcmp((const char *)sa1
+ dom
->dom_sa_cmpofs
,
308 (const char *)sa2
+ dom
->dom_sa_cmpofs
,
309 MIN(dom
->dom_sa_cmplen
,
310 len
- MIN(len
, dom
->dom_sa_cmpofs
)))) != 0)
313 return MIN(dom
->dom_sa_cmplen
+ dom
->dom_sa_cmpofs
, sa1
->sa_len
) -
314 MIN(dom
->dom_sa_cmplen
+ dom
->dom_sa_cmpofs
, sa2
->sa_len
);
318 sockaddr_dup(const struct sockaddr
*src
, int flags
)
320 struct sockaddr
*dst
;
322 if ((dst
= sockaddr_alloc(src
->sa_family
, src
->sa_len
, flags
)) == NULL
)
325 return sockaddr_copy(dst
, dst
->sa_len
, src
);
329 sockaddr_free(struct sockaddr
*sa
)
331 free(sa
, M_SOCKADDR
);
335 * sysctl helper to stuff PF_LOCAL pcbs into sysctl structures
338 sysctl_dounpcb(struct kinfo_pcb
*pcb
, const struct socket
*so
)
340 struct unpcb
*unp
= sotounpcb(so
);
341 struct sockaddr_un
*un
= unp
->unp_addr
;
343 memset(pcb
, 0, sizeof(*pcb
));
345 pcb
->ki_family
= so
->so_proto
->pr_domain
->dom_family
;
346 pcb
->ki_type
= so
->so_proto
->pr_type
;
347 pcb
->ki_protocol
= so
->so_proto
->pr_protocol
;
348 pcb
->ki_pflags
= unp
->unp_flags
;
350 pcb
->ki_pcbaddr
= PTRTOUINT64(unp
);
351 /* pcb->ki_ppcbaddr = unp has no ppcb... */
352 pcb
->ki_sockaddr
= PTRTOUINT64(so
);
354 pcb
->ki_sostate
= so
->so_state
;
355 /* pcb->ki_prstate = unp has no state... */
357 pcb
->ki_rcvq
= so
->so_rcv
.sb_cc
;
358 pcb
->ki_sndq
= so
->so_snd
.sb_cc
;
360 un
= (struct sockaddr_un
*)&pcb
->ki_src
;
362 * local domain sockets may bind without having a local
365 if (unp
->unp_addr
!= NULL
) {
366 un
->sun_len
= unp
->unp_addr
->sun_len
;
367 un
->sun_family
= unp
->unp_addr
->sun_family
;
368 strlcpy(un
->sun_path
, unp
->unp_addr
->sun_path
,
372 un
->sun_len
= offsetof(struct sockaddr_un
, sun_path
);
373 un
->sun_family
= pcb
->ki_family
;
375 if (unp
->unp_conn
!= NULL
) {
376 un
= (struct sockaddr_un
*)&pcb
->ki_dst
;
377 if (unp
->unp_conn
->unp_addr
!= NULL
) {
378 un
->sun_len
= unp
->unp_conn
->unp_addr
->sun_len
;
379 un
->sun_family
= unp
->unp_conn
->unp_addr
->sun_family
;
380 un
->sun_family
= unp
->unp_conn
->unp_addr
->sun_family
;
381 strlcpy(un
->sun_path
, unp
->unp_conn
->unp_addr
->sun_path
,
385 un
->sun_len
= offsetof(struct sockaddr_un
, sun_path
);
386 un
->sun_family
= pcb
->ki_family
;
390 pcb
->ki_inode
= unp
->unp_ino
;
391 pcb
->ki_vnode
= PTRTOUINT64(unp
->unp_vnode
);
392 pcb
->ki_conn
= PTRTOUINT64(unp
->unp_conn
);
393 pcb
->ki_refs
= PTRTOUINT64(unp
->unp_refs
);
394 pcb
->ki_nextref
= PTRTOUINT64(unp
->unp_nextref
);
398 sysctl_unpcblist(SYSCTLFN_ARGS
)
400 struct file
*fp
, *dfp
, *np
;
402 struct kinfo_pcb pcb
;
405 size_t len
, needed
, elem_size
, out_size
;
406 int error
, elem_count
, pf
, type
, pf2
;
408 if (namelen
== 1 && name
[0] == CTL_QUERY
)
409 return sysctl_query(SYSCTLFN_CALL(rnode
));
417 elem_count
= name
[3];
418 if (elem_size
!= sizeof(pcb
))
422 elem_size
= sizeof(pcb
);
423 elem_count
= INT_MAX
;
429 out_size
= elem_size
;
432 if (name
- oname
!= 4)
437 pf2
= (oldp
== NULL
) ? 0 : pf
;
440 * allocate dummy file descriptor to make position in list.
443 if ((dfp
= fgetdummy()) == NULL
) {
449 * there's no "list" of local domain sockets, so we have
450 * to walk the file list looking for them. :-/
452 mutex_enter(&filelist_lock
);
453 LIST_FOREACH(fp
, &filehead
, f_list
) {
454 np
= LIST_NEXT(fp
, f_list
);
455 if (fp
->f_count
== 0 || fp
->f_type
!= DTYPE_SOCKET
||
458 so
= (struct socket
*)fp
->f_data
;
459 if (so
->so_type
!= type
)
461 if (so
->so_proto
->pr_domain
->dom_family
!= pf
)
463 if (kauth_authorize_network(l
->l_cred
, KAUTH_NETWORK_SOCKET
,
464 KAUTH_REQ_NETWORK_SOCKET_CANSEE
, so
, NULL
, NULL
) != 0)
466 if (len
>= elem_size
&& elem_count
> 0) {
467 mutex_enter(&fp
->f_lock
);
469 mutex_exit(&fp
->f_lock
);
470 LIST_INSERT_AFTER(fp
, dfp
, f_list
);
471 mutex_exit(&filelist_lock
);
472 sysctl_dounpcb(&pcb
, so
);
473 error
= copyout(&pcb
, dp
, out_size
);
475 mutex_enter(&filelist_lock
);
476 np
= LIST_NEXT(dfp
, f_list
);
477 LIST_REMOVE(dfp
, f_list
);
484 if (elem_count
> 0 && elem_count
!= INT_MAX
)
487 mutex_exit(&filelist_lock
);
491 *oldlenp
+= PCB_SLOP
* sizeof(struct kinfo_pcb
);
498 sysctl_net_setup(void)
501 KASSERT(domain_sysctllog
== NULL
);
502 sysctl_createv(&domain_sysctllog
, 0, NULL
, NULL
,
504 CTLTYPE_NODE
, "net", NULL
,
507 sysctl_createv(&domain_sysctllog
, 0, NULL
, NULL
,
509 CTLTYPE_NODE
, "local",
510 SYSCTL_DESCR("PF_LOCAL related settings"),
512 CTL_NET
, PF_LOCAL
, CTL_EOL
);
513 sysctl_createv(&domain_sysctllog
, 0, NULL
, NULL
,
515 CTLTYPE_NODE
, "stream",
516 SYSCTL_DESCR("SOCK_STREAM settings"),
518 CTL_NET
, PF_LOCAL
, SOCK_STREAM
, CTL_EOL
);
519 sysctl_createv(&domain_sysctllog
, 0, NULL
, NULL
,
521 CTLTYPE_NODE
, "dgram",
522 SYSCTL_DESCR("SOCK_DGRAM settings"),
524 CTL_NET
, PF_LOCAL
, SOCK_DGRAM
, CTL_EOL
);
526 sysctl_createv(&domain_sysctllog
, 0, NULL
, NULL
,
528 CTLTYPE_STRUCT
, "pcblist",
529 SYSCTL_DESCR("SOCK_STREAM protocol control block list"),
530 sysctl_unpcblist
, 0, NULL
, 0,
531 CTL_NET
, PF_LOCAL
, SOCK_STREAM
, CTL_CREATE
, CTL_EOL
);
532 sysctl_createv(&domain_sysctllog
, 0, NULL
, NULL
,
534 CTLTYPE_STRUCT
, "pcblist",
535 SYSCTL_DESCR("SOCK_DGRAM protocol control block list"),
536 sysctl_unpcblist
, 0, NULL
, 0,
537 CTL_NET
, PF_LOCAL
, SOCK_DGRAM
, CTL_CREATE
, CTL_EOL
);
541 pfctlinput(int cmd
, const struct sockaddr
*sa
)
544 const struct protosw
*pr
;
547 for (pr
= dp
->dom_protosw
; pr
< dp
->dom_protoswNPROTOSW
; pr
++) {
548 if (pr
->pr_ctlinput
!= NULL
)
549 (*pr
->pr_ctlinput
)(cmd
, sa
, NULL
);
555 pfctlinput2(int cmd
, const struct sockaddr
*sa
, void *ctlparam
)
558 const struct protosw
*pr
;
565 * the check must be made by xx_ctlinput() anyways, to
566 * make sure we use data item pointed to by ctlparam in
567 * correct way. the following check is made just for safety.
569 if (dp
->dom_family
!= sa
->sa_family
)
572 for (pr
= dp
->dom_protosw
; pr
< dp
->dom_protoswNPROTOSW
; pr
++) {
573 if (pr
->pr_ctlinput
!= NULL
)
574 (*pr
->pr_ctlinput
)(cmd
, sa
, ctlparam
);
580 pfslowtimo(void *arg
)
583 const struct protosw
*pr
;
588 for (pr
= dp
->dom_protosw
; pr
< dp
->dom_protoswNPROTOSW
; pr
++)
590 (*pr
->pr_slowtimo
)();
592 callout_schedule(&pfslowtimo_ch
, hz
/ 2);
596 pffasttimo(void *arg
)
599 const struct protosw
*pr
;
604 for (pr
= dp
->dom_protosw
; pr
< dp
->dom_protoswNPROTOSW
; pr
++)
606 (*pr
->pr_fasttimo
)();
608 callout_schedule(&pffasttimo_ch
, hz
/ 5);