1 | /* $NetBSD: uipc_domain.c,v 1.96 2014/12/02 19:45:58 christos Exp $ */ |
2 | |
3 | /* |
4 | * Copyright (c) 1982, 1986, 1993 |
5 | * The Regents of the University of California. All rights reserved. |
6 | * |
7 | * Redistribution and use in source and binary forms, with or without |
8 | * modification, are permitted provided that the following conditions |
9 | * are met: |
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. |
18 | * |
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 |
29 | * SUCH DAMAGE. |
30 | * |
31 | * @(#)uipc_domain.c 8.3 (Berkeley) 2/14/95 |
32 | */ |
33 | |
34 | #include <sys/cdefs.h> |
35 | __KERNEL_RCSID(0, "$NetBSD: uipc_domain.c,v 1.96 2014/12/02 19:45:58 christos Exp $" ); |
36 | |
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> |
42 | #include <sys/mbuf.h> |
43 | #include <sys/time.h> |
44 | #include <sys/kernel.h> |
45 | #include <sys/systm.h> |
46 | #include <sys/callout.h> |
47 | #include <sys/queue.h> |
48 | #include <sys/proc.h> |
49 | #include <sys/sysctl.h> |
50 | #include <sys/un.h> |
51 | #include <sys/unpcb.h> |
52 | #include <sys/file.h> |
53 | #include <sys/filedesc.h> |
54 | #include <sys/kauth.h> |
55 | |
56 | #include <netatalk/at.h> |
57 | #include <net/if_dl.h> |
58 | #include <netinet/in.h> |
59 | |
60 | MALLOC_DECLARE(M_SOCKADDR); |
61 | |
62 | MALLOC_DEFINE(M_SOCKADDR, "sockaddr" , "socket endpoints" ); |
63 | |
64 | void pffasttimo(void *); |
65 | void pfslowtimo(void *); |
66 | |
67 | struct domainhead domains = STAILQ_HEAD_INITIALIZER(domains); |
68 | static struct domain *domain_array[AF_MAX]; |
69 | |
70 | callout_t pffasttimo_ch, pfslowtimo_ch; |
71 | |
72 | /* |
73 | * Current time values for fast and slow timeouts. We can use u_int |
74 | * relatively safely. The fast timer will roll over in 27 years and |
75 | * the slow timer in 68 years. |
76 | */ |
77 | u_int pfslowtimo_now; |
78 | u_int pffasttimo_now; |
79 | |
80 | static struct sysctllog *domain_sysctllog; |
81 | static void sysctl_net_setup(void); |
82 | |
83 | /* ensure successful linkage even without any domains in link sets */ |
84 | static struct domain domain_dummy; |
85 | __link_set_add_rodata(domains,domain_dummy); |
86 | |
87 | void |
88 | domaininit(bool attach) |
89 | { |
90 | __link_set_decl(domains, struct domain); |
91 | struct domain * const * dpp; |
92 | struct domain *rt_domain = NULL; |
93 | |
94 | sysctl_net_setup(); |
95 | |
96 | /* |
97 | * Add all of the domains. Make sure the PF_ROUTE |
98 | * domain is added last. |
99 | */ |
100 | if (attach) { |
101 | __link_set_foreach(dpp, domains) { |
102 | if (*dpp == &domain_dummy) |
103 | continue; |
104 | if ((*dpp)->dom_family == PF_ROUTE) |
105 | rt_domain = *dpp; |
106 | else |
107 | domain_attach(*dpp); |
108 | } |
109 | if (rt_domain) |
110 | domain_attach(rt_domain); |
111 | } |
112 | |
113 | callout_init(&pffasttimo_ch, CALLOUT_MPSAFE); |
114 | callout_init(&pfslowtimo_ch, CALLOUT_MPSAFE); |
115 | |
116 | callout_reset(&pffasttimo_ch, 1, pffasttimo, NULL); |
117 | callout_reset(&pfslowtimo_ch, 1, pfslowtimo, NULL); |
118 | } |
119 | |
120 | void |
121 | domain_attach(struct domain *dp) |
122 | { |
123 | const struct protosw *pr; |
124 | |
125 | STAILQ_INSERT_TAIL(&domains, dp, dom_link); |
126 | if (dp->dom_family < __arraycount(domain_array)) |
127 | domain_array[dp->dom_family] = dp; |
128 | |
129 | if (dp->dom_init) |
130 | (*dp->dom_init)(); |
131 | |
132 | #ifdef MBUFTRACE |
133 | if (dp->dom_mowner.mo_name[0] == '\0') { |
134 | strncpy(dp->dom_mowner.mo_name, dp->dom_name, |
135 | sizeof(dp->dom_mowner.mo_name)); |
136 | MOWNER_ATTACH(&dp->dom_mowner); |
137 | } |
138 | #endif |
139 | for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++) { |
140 | if (pr->pr_init) |
141 | (*pr->pr_init)(); |
142 | } |
143 | |
144 | if (max_linkhdr < 16) /* XXX */ |
145 | max_linkhdr = 16; |
146 | max_hdr = max_linkhdr + max_protohdr; |
147 | max_datalen = MHLEN - max_hdr; |
148 | } |
149 | |
150 | struct domain * |
151 | pffinddomain(int family) |
152 | { |
153 | struct domain *dp; |
154 | |
155 | if (family < __arraycount(domain_array) && domain_array[family] != NULL) |
156 | return domain_array[family]; |
157 | |
158 | DOMAIN_FOREACH(dp) |
159 | if (dp->dom_family == family) |
160 | return dp; |
161 | return NULL; |
162 | } |
163 | |
164 | const struct protosw * |
165 | pffindtype(int family, int type) |
166 | { |
167 | struct domain *dp; |
168 | const struct protosw *pr; |
169 | |
170 | dp = pffinddomain(family); |
171 | if (dp == NULL) |
172 | return NULL; |
173 | |
174 | for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++) |
175 | if (pr->pr_type && pr->pr_type == type) |
176 | return pr; |
177 | |
178 | return NULL; |
179 | } |
180 | |
181 | const struct protosw * |
182 | pffindproto(int family, int protocol, int type) |
183 | { |
184 | struct domain *dp; |
185 | const struct protosw *pr; |
186 | const struct protosw *maybe = NULL; |
187 | |
188 | if (family == 0) |
189 | return NULL; |
190 | |
191 | dp = pffinddomain(family); |
192 | if (dp == NULL) |
193 | return NULL; |
194 | |
195 | for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++) { |
196 | if ((pr->pr_protocol == protocol) && (pr->pr_type == type)) |
197 | return pr; |
198 | |
199 | if (type == SOCK_RAW && pr->pr_type == SOCK_RAW && |
200 | pr->pr_protocol == 0 && maybe == NULL) |
201 | maybe = pr; |
202 | } |
203 | return maybe; |
204 | } |
205 | |
206 | void * |
207 | sockaddr_addr(struct sockaddr *sa, socklen_t *slenp) |
208 | { |
209 | const struct domain *dom; |
210 | |
211 | if ((dom = pffinddomain(sa->sa_family)) == NULL || |
212 | dom->dom_sockaddr_addr == NULL) |
213 | return NULL; |
214 | |
215 | return (*dom->dom_sockaddr_addr)(sa, slenp); |
216 | } |
217 | |
218 | const void * |
219 | sockaddr_const_addr(const struct sockaddr *sa, socklen_t *slenp) |
220 | { |
221 | const struct domain *dom; |
222 | |
223 | if ((dom = pffinddomain(sa->sa_family)) == NULL || |
224 | dom->dom_sockaddr_const_addr == NULL) |
225 | return NULL; |
226 | |
227 | return (*dom->dom_sockaddr_const_addr)(sa, slenp); |
228 | } |
229 | |
230 | const struct sockaddr * |
231 | sockaddr_any_by_family(int family) |
232 | { |
233 | const struct domain *dom; |
234 | |
235 | if ((dom = pffinddomain(family)) == NULL) |
236 | return NULL; |
237 | |
238 | return dom->dom_sa_any; |
239 | } |
240 | |
241 | const struct sockaddr * |
242 | sockaddr_any(const struct sockaddr *sa) |
243 | { |
244 | return sockaddr_any_by_family(sa->sa_family); |
245 | } |
246 | |
247 | const void * |
248 | sockaddr_anyaddr(const struct sockaddr *sa, socklen_t *slenp) |
249 | { |
250 | const struct sockaddr *any; |
251 | |
252 | if ((any = sockaddr_any(sa)) == NULL) |
253 | return NULL; |
254 | |
255 | return sockaddr_const_addr(any, slenp); |
256 | } |
257 | |
258 | #ifdef DIAGNOSTIC |
259 | static void |
260 | sockaddr_checklen(const struct sockaddr *sa) |
261 | { |
262 | socklen_t len = 0; |
263 | switch (sa->sa_family) { |
264 | case AF_INET: |
265 | len = sizeof(struct sockaddr_in); |
266 | break; |
267 | case AF_INET6: |
268 | len = sizeof(struct sockaddr_in6); |
269 | break; |
270 | case AF_UNIX: |
271 | len = sizeof(struct sockaddr_un); |
272 | break; |
273 | case AF_LINK: |
274 | len = sizeof(struct sockaddr_dl); |
275 | // As long as it is not 0... |
276 | if (sa->sa_len != 0) |
277 | return; |
278 | break; |
279 | case AF_APPLETALK: |
280 | len = sizeof(struct sockaddr_at); |
281 | break; |
282 | default: |
283 | printf("%s: Unhandled af=%hhu socklen=%hhu\n" , __func__, |
284 | sa->sa_family, sa->sa_len); |
285 | return; |
286 | } |
287 | if (len != sa->sa_len) { |
288 | char buf[512]; |
289 | sockaddr_format(sa, buf, sizeof(buf)); |
290 | printf("%s: %p bad len af=%hhu socklen=%hhu len=%u [%s]\n" , |
291 | __func__, sa, sa->sa_family, sa->sa_len, |
292 | (unsigned)len, buf); |
293 | } |
294 | } |
295 | #else |
296 | #define sockaddr_checklen(sa) ((void)0) |
297 | #endif |
298 | |
299 | struct sockaddr * |
300 | sockaddr_alloc(sa_family_t af, socklen_t socklen, int flags) |
301 | { |
302 | struct sockaddr *sa; |
303 | socklen_t reallen = MAX(socklen, offsetof(struct sockaddr, sa_data[0])); |
304 | |
305 | if ((sa = malloc(reallen, M_SOCKADDR, flags)) == NULL) |
306 | return NULL; |
307 | |
308 | sa->sa_family = af; |
309 | sa->sa_len = reallen; |
310 | sockaddr_checklen(sa); |
311 | return sa; |
312 | } |
313 | |
314 | struct sockaddr * |
315 | sockaddr_copy(struct sockaddr *dst, socklen_t socklen, |
316 | const struct sockaddr *src) |
317 | { |
318 | if (__predict_false(socklen < src->sa_len)) { |
319 | panic("%s: source too long, %d < %d bytes" , __func__, socklen, |
320 | src->sa_len); |
321 | } |
322 | sockaddr_checklen(src); |
323 | return memcpy(dst, src, src->sa_len); |
324 | } |
325 | |
326 | struct sockaddr * |
327 | sockaddr_externalize(struct sockaddr *dst, socklen_t socklen, |
328 | const struct sockaddr *src) |
329 | { |
330 | struct domain *dom; |
331 | |
332 | dom = pffinddomain(src->sa_family); |
333 | |
334 | if (dom != NULL && dom->dom_sockaddr_externalize != NULL) |
335 | return (*dom->dom_sockaddr_externalize)(dst, socklen, src); |
336 | |
337 | return sockaddr_copy(dst, socklen, src); |
338 | } |
339 | |
340 | int |
341 | sockaddr_cmp(const struct sockaddr *sa1, const struct sockaddr *sa2) |
342 | { |
343 | int len, rc; |
344 | struct domain *dom; |
345 | |
346 | if (sa1->sa_family != sa2->sa_family) |
347 | return sa1->sa_family - sa2->sa_family; |
348 | |
349 | dom = pffinddomain(sa1->sa_family); |
350 | |
351 | if (dom != NULL && dom->dom_sockaddr_cmp != NULL) |
352 | return (*dom->dom_sockaddr_cmp)(sa1, sa2); |
353 | |
354 | len = MIN(sa1->sa_len, sa2->sa_len); |
355 | |
356 | if (dom == NULL || dom->dom_sa_cmplen == 0) { |
357 | if ((rc = memcmp(sa1, sa2, len)) != 0) |
358 | return rc; |
359 | return sa1->sa_len - sa2->sa_len; |
360 | } |
361 | |
362 | if ((rc = memcmp((const char *)sa1 + dom->dom_sa_cmpofs, |
363 | (const char *)sa2 + dom->dom_sa_cmpofs, |
364 | MIN(dom->dom_sa_cmplen, |
365 | len - MIN(len, dom->dom_sa_cmpofs)))) != 0) |
366 | return rc; |
367 | |
368 | return MIN(dom->dom_sa_cmplen + dom->dom_sa_cmpofs, sa1->sa_len) - |
369 | MIN(dom->dom_sa_cmplen + dom->dom_sa_cmpofs, sa2->sa_len); |
370 | } |
371 | |
372 | struct sockaddr * |
373 | sockaddr_dup(const struct sockaddr *src, int flags) |
374 | { |
375 | struct sockaddr *dst; |
376 | |
377 | if ((dst = sockaddr_alloc(src->sa_family, src->sa_len, flags)) == NULL) |
378 | return NULL; |
379 | |
380 | return sockaddr_copy(dst, dst->sa_len, src); |
381 | } |
382 | |
383 | void |
384 | sockaddr_free(struct sockaddr *sa) |
385 | { |
386 | free(sa, M_SOCKADDR); |
387 | } |
388 | |
389 | static int |
390 | sun_print(char *buf, size_t len, const void *v) |
391 | { |
392 | const struct sockaddr_un *sun = v; |
393 | return snprintf(buf, len, "%s" , sun->sun_path); |
394 | } |
395 | |
396 | int |
397 | sockaddr_format(const struct sockaddr *sa, char *buf, size_t len) |
398 | { |
399 | size_t plen = 0; |
400 | |
401 | if (sa == NULL) |
402 | return strlcpy(buf, "(null)" , len); |
403 | |
404 | switch (sa->sa_family) { |
405 | case AF_LOCAL: |
406 | plen = strlcpy(buf, "unix: " , len); |
407 | break; |
408 | case AF_INET: |
409 | plen = strlcpy(buf, "inet: " , len); |
410 | break; |
411 | case AF_INET6: |
412 | plen = strlcpy(buf, "inet6: " , len); |
413 | break; |
414 | case AF_LINK: |
415 | plen = strlcpy(buf, "link: " , len); |
416 | break; |
417 | case AF_APPLETALK: |
418 | plen = strlcpy(buf, "atalk: " , len); |
419 | break; |
420 | default: |
421 | return snprintf(buf, len, "(unknown socket family %d)" , |
422 | (int)sa->sa_family); |
423 | } |
424 | |
425 | buf += plen; |
426 | if (plen > len) |
427 | len = 0; |
428 | else |
429 | len -= plen; |
430 | |
431 | switch (sa->sa_family) { |
432 | case AF_LOCAL: |
433 | return sun_print(buf, len, sa); |
434 | case AF_INET: |
435 | return sin_print(buf, len, sa); |
436 | case AF_INET6: |
437 | return sin6_print(buf, len, sa); |
438 | case AF_LINK: |
439 | return sdl_print(buf, len, sa); |
440 | case AF_APPLETALK: |
441 | return sat_print(buf, len, sa); |
442 | default: |
443 | panic("bad family %hhu" , sa->sa_family); |
444 | } |
445 | } |
446 | |
447 | /* |
448 | * sysctl helper to stuff PF_LOCAL pcbs into sysctl structures |
449 | */ |
450 | static void |
451 | sysctl_dounpcb(struct kinfo_pcb *pcb, const struct socket *so) |
452 | { |
453 | struct unpcb *unp = sotounpcb(so); |
454 | struct sockaddr_un *un = unp->unp_addr; |
455 | |
456 | memset(pcb, 0, sizeof(*pcb)); |
457 | |
458 | pcb->ki_family = so->so_proto->pr_domain->dom_family; |
459 | pcb->ki_type = so->so_proto->pr_type; |
460 | pcb->ki_protocol = so->so_proto->pr_protocol; |
461 | pcb->ki_pflags = unp->unp_flags; |
462 | |
463 | pcb->ki_pcbaddr = PTRTOUINT64(unp); |
464 | /* pcb->ki_ppcbaddr = unp has no ppcb... */ |
465 | pcb->ki_sockaddr = PTRTOUINT64(so); |
466 | |
467 | pcb->ki_sostate = so->so_state; |
468 | /* pcb->ki_prstate = unp has no state... */ |
469 | |
470 | pcb->ki_rcvq = so->so_rcv.sb_cc; |
471 | pcb->ki_sndq = so->so_snd.sb_cc; |
472 | |
473 | un = (struct sockaddr_un *)pcb->ki_spad; |
474 | /* |
475 | * local domain sockets may bind without having a local |
476 | * endpoint. bleah! |
477 | */ |
478 | if (unp->unp_addr != NULL) { |
479 | /* |
480 | * We've added one to sun_len when allocating to |
481 | * hold terminating NUL which we want here. See |
482 | * makeun(). |
483 | */ |
484 | memcpy(un, unp->unp_addr, |
485 | min(sizeof(pcb->ki_spad), unp->unp_addr->sun_len + 1)); |
486 | } |
487 | else { |
488 | un->sun_len = offsetof(struct sockaddr_un, sun_path); |
489 | un->sun_family = pcb->ki_family; |
490 | } |
491 | if (unp->unp_conn != NULL) { |
492 | un = (struct sockaddr_un *)pcb->ki_dpad; |
493 | if (unp->unp_conn->unp_addr != NULL) { |
494 | memcpy(un, unp->unp_conn->unp_addr, |
495 | min(sizeof(pcb->ki_dpad), unp->unp_conn->unp_addr->sun_len + 1)); |
496 | } |
497 | else { |
498 | un->sun_len = offsetof(struct sockaddr_un, sun_path); |
499 | un->sun_family = pcb->ki_family; |
500 | } |
501 | } |
502 | |
503 | pcb->ki_inode = unp->unp_ino; |
504 | pcb->ki_vnode = PTRTOUINT64(unp->unp_vnode); |
505 | pcb->ki_conn = PTRTOUINT64(unp->unp_conn); |
506 | pcb->ki_refs = PTRTOUINT64(unp->unp_refs); |
507 | pcb->ki_nextref = PTRTOUINT64(unp->unp_nextref); |
508 | } |
509 | |
510 | static int |
511 | sysctl_unpcblist(SYSCTLFN_ARGS) |
512 | { |
513 | struct file *fp, *dfp; |
514 | struct socket *so; |
515 | struct kinfo_pcb pcb; |
516 | char *dp; |
517 | size_t len, needed, elem_size, out_size; |
518 | int error, elem_count, pf, type; |
519 | |
520 | if (namelen == 1 && name[0] == CTL_QUERY) |
521 | return sysctl_query(SYSCTLFN_CALL(rnode)); |
522 | |
523 | if (namelen != 4) |
524 | return EINVAL; |
525 | |
526 | if (oldp != NULL) { |
527 | len = *oldlenp; |
528 | elem_size = name[2]; |
529 | elem_count = name[3]; |
530 | if (elem_size != sizeof(pcb)) |
531 | return EINVAL; |
532 | } else { |
533 | len = 0; |
534 | elem_size = sizeof(pcb); |
535 | elem_count = INT_MAX; |
536 | } |
537 | error = 0; |
538 | dp = oldp; |
539 | out_size = elem_size; |
540 | needed = 0; |
541 | |
542 | if (name - oname != 4) |
543 | return EINVAL; |
544 | |
545 | pf = oname[1]; |
546 | type = oname[2]; |
547 | |
548 | /* |
549 | * allocate dummy file descriptor to make position in list. |
550 | */ |
551 | sysctl_unlock(); |
552 | if ((dfp = fgetdummy()) == NULL) { |
553 | sysctl_relock(); |
554 | return ENOMEM; |
555 | } |
556 | |
557 | /* |
558 | * there's no "list" of local domain sockets, so we have |
559 | * to walk the file list looking for them. :-/ |
560 | */ |
561 | mutex_enter(&filelist_lock); |
562 | LIST_FOREACH(fp, &filehead, f_list) { |
563 | if (fp->f_count == 0 || fp->f_type != DTYPE_SOCKET || |
564 | fp->f_socket == NULL) |
565 | continue; |
566 | so = fp->f_socket; |
567 | if (so->so_type != type) |
568 | continue; |
569 | if (so->so_proto->pr_domain->dom_family != pf) |
570 | continue; |
571 | if (kauth_authorize_network(l->l_cred, KAUTH_NETWORK_SOCKET, |
572 | KAUTH_REQ_NETWORK_SOCKET_CANSEE, so, NULL, NULL) != 0) |
573 | continue; |
574 | if (len >= elem_size && elem_count > 0) { |
575 | mutex_enter(&fp->f_lock); |
576 | fp->f_count++; |
577 | mutex_exit(&fp->f_lock); |
578 | LIST_INSERT_AFTER(fp, dfp, f_list); |
579 | mutex_exit(&filelist_lock); |
580 | sysctl_dounpcb(&pcb, so); |
581 | error = copyout(&pcb, dp, out_size); |
582 | closef(fp); |
583 | mutex_enter(&filelist_lock); |
584 | LIST_REMOVE(dfp, f_list); |
585 | if (error) |
586 | break; |
587 | dp += elem_size; |
588 | len -= elem_size; |
589 | } |
590 | needed += elem_size; |
591 | if (elem_count > 0 && elem_count != INT_MAX) |
592 | elem_count--; |
593 | } |
594 | mutex_exit(&filelist_lock); |
595 | fputdummy(dfp); |
596 | *oldlenp = needed; |
597 | if (oldp == NULL) |
598 | *oldlenp += PCB_SLOP * sizeof(struct kinfo_pcb); |
599 | sysctl_relock(); |
600 | |
601 | return error; |
602 | } |
603 | |
604 | static void |
605 | sysctl_net_setup(void) |
606 | { |
607 | |
608 | KASSERT(domain_sysctllog == NULL); |
609 | sysctl_createv(&domain_sysctllog, 0, NULL, NULL, |
610 | CTLFLAG_PERMANENT, |
611 | CTLTYPE_NODE, "local" , |
612 | SYSCTL_DESCR("PF_LOCAL related settings" ), |
613 | NULL, 0, NULL, 0, |
614 | CTL_NET, PF_LOCAL, CTL_EOL); |
615 | sysctl_createv(&domain_sysctllog, 0, NULL, NULL, |
616 | CTLFLAG_PERMANENT, |
617 | CTLTYPE_NODE, "stream" , |
618 | SYSCTL_DESCR("SOCK_STREAM settings" ), |
619 | NULL, 0, NULL, 0, |
620 | CTL_NET, PF_LOCAL, SOCK_STREAM, CTL_EOL); |
621 | sysctl_createv(&domain_sysctllog, 0, NULL, NULL, |
622 | CTLFLAG_PERMANENT, |
623 | CTLTYPE_NODE, "seqpacket" , |
624 | SYSCTL_DESCR("SOCK_SEQPACKET settings" ), |
625 | NULL, 0, NULL, 0, |
626 | CTL_NET, PF_LOCAL, SOCK_SEQPACKET, CTL_EOL); |
627 | sysctl_createv(&domain_sysctllog, 0, NULL, NULL, |
628 | CTLFLAG_PERMANENT, |
629 | CTLTYPE_NODE, "dgram" , |
630 | SYSCTL_DESCR("SOCK_DGRAM settings" ), |
631 | NULL, 0, NULL, 0, |
632 | CTL_NET, PF_LOCAL, SOCK_DGRAM, CTL_EOL); |
633 | |
634 | sysctl_createv(&domain_sysctllog, 0, NULL, NULL, |
635 | CTLFLAG_PERMANENT, |
636 | CTLTYPE_STRUCT, "pcblist" , |
637 | SYSCTL_DESCR("SOCK_STREAM protocol control block list" ), |
638 | sysctl_unpcblist, 0, NULL, 0, |
639 | CTL_NET, PF_LOCAL, SOCK_STREAM, CTL_CREATE, CTL_EOL); |
640 | sysctl_createv(&domain_sysctllog, 0, NULL, NULL, |
641 | CTLFLAG_PERMANENT, |
642 | CTLTYPE_STRUCT, "pcblist" , |
643 | SYSCTL_DESCR("SOCK_SEQPACKET protocol control " |
644 | "block list" ), |
645 | sysctl_unpcblist, 0, NULL, 0, |
646 | CTL_NET, PF_LOCAL, SOCK_SEQPACKET, CTL_CREATE, CTL_EOL); |
647 | sysctl_createv(&domain_sysctllog, 0, NULL, NULL, |
648 | CTLFLAG_PERMANENT, |
649 | CTLTYPE_STRUCT, "pcblist" , |
650 | SYSCTL_DESCR("SOCK_DGRAM protocol control block list" ), |
651 | sysctl_unpcblist, 0, NULL, 0, |
652 | CTL_NET, PF_LOCAL, SOCK_DGRAM, CTL_CREATE, CTL_EOL); |
653 | } |
654 | |
655 | void |
656 | pfctlinput(int cmd, const struct sockaddr *sa) |
657 | { |
658 | struct domain *dp; |
659 | const struct protosw *pr; |
660 | |
661 | DOMAIN_FOREACH(dp) { |
662 | for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++) { |
663 | if (pr->pr_ctlinput != NULL) |
664 | (*pr->pr_ctlinput)(cmd, sa, NULL); |
665 | } |
666 | } |
667 | } |
668 | |
669 | void |
670 | pfctlinput2(int cmd, const struct sockaddr *sa, void *ctlparam) |
671 | { |
672 | struct domain *dp; |
673 | const struct protosw *pr; |
674 | |
675 | if (sa == NULL) |
676 | return; |
677 | |
678 | DOMAIN_FOREACH(dp) { |
679 | /* |
680 | * the check must be made by xx_ctlinput() anyways, to |
681 | * make sure we use data item pointed to by ctlparam in |
682 | * correct way. the following check is made just for safety. |
683 | */ |
684 | if (dp->dom_family != sa->sa_family) |
685 | continue; |
686 | |
687 | for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++) { |
688 | if (pr->pr_ctlinput != NULL) |
689 | (*pr->pr_ctlinput)(cmd, sa, ctlparam); |
690 | } |
691 | } |
692 | } |
693 | |
694 | void |
695 | pfslowtimo(void *arg) |
696 | { |
697 | struct domain *dp; |
698 | const struct protosw *pr; |
699 | |
700 | pfslowtimo_now++; |
701 | |
702 | DOMAIN_FOREACH(dp) { |
703 | for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++) |
704 | if (pr->pr_slowtimo) |
705 | (*pr->pr_slowtimo)(); |
706 | } |
707 | callout_schedule(&pfslowtimo_ch, hz / PR_SLOWHZ); |
708 | } |
709 | |
710 | void |
711 | pffasttimo(void *arg) |
712 | { |
713 | struct domain *dp; |
714 | const struct protosw *pr; |
715 | |
716 | pffasttimo_now++; |
717 | |
718 | DOMAIN_FOREACH(dp) { |
719 | for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++) |
720 | if (pr->pr_fasttimo) |
721 | (*pr->pr_fasttimo)(); |
722 | } |
723 | callout_schedule(&pffasttimo_ch, hz / PR_FASTHZ); |
724 | } |
725 | |