]>
Commit | Line | Data |
---|---|---|
1c79356b | 1 | /* |
d9a64523 | 2 | * Copyright (c) 1998-2018 Apple Inc. All rights reserved. |
5d5c5d0d | 3 | * |
2d21ac55 | 4 | * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ |
39236c6e | 5 | * |
2d21ac55 A |
6 | * This file contains Original Code and/or Modifications of Original Code |
7 | * as defined in and that are subject to the Apple Public Source License | |
8 | * Version 2.0 (the 'License'). You may not use this file except in | |
9 | * compliance with the License. The rights granted to you under the License | |
10 | * may not be used to create, or enable the creation or redistribution of, | |
11 | * unlawful or unlicensed copies of an Apple operating system, or to | |
12 | * circumvent, violate, or enable the circumvention or violation of, any | |
13 | * terms of an Apple operating system software license agreement. | |
39236c6e | 14 | * |
2d21ac55 A |
15 | * Please obtain a copy of the License at |
16 | * http://www.opensource.apple.com/apsl/ and read it before using this file. | |
39236c6e | 17 | * |
2d21ac55 A |
18 | * The Original Code and all software distributed under the License are |
19 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
8f6c56a5 A |
20 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, |
21 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
2d21ac55 A |
22 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. |
23 | * Please see the License for the specific language governing rights and | |
24 | * limitations under the License. | |
39236c6e | 25 | * |
2d21ac55 | 26 | * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ |
1c79356b | 27 | */ |
1c79356b A |
28 | /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */ |
29 | /* | |
30 | * Copyright (c) 1982, 1986, 1993 | |
31 | * The Regents of the University of California. All rights reserved. | |
32 | * | |
33 | * Redistribution and use in source and binary forms, with or without | |
34 | * modification, are permitted provided that the following conditions | |
35 | * are met: | |
36 | * 1. Redistributions of source code must retain the above copyright | |
37 | * notice, this list of conditions and the following disclaimer. | |
38 | * 2. Redistributions in binary form must reproduce the above copyright | |
39 | * notice, this list of conditions and the following disclaimer in the | |
40 | * documentation and/or other materials provided with the distribution. | |
41 | * 3. All advertising materials mentioning features or use of this software | |
42 | * must display the following acknowledgement: | |
43 | * This product includes software developed by the University of | |
44 | * California, Berkeley and its contributors. | |
45 | * 4. Neither the name of the University nor the names of its contributors | |
46 | * may be used to endorse or promote products derived from this software | |
47 | * without specific prior written permission. | |
48 | * | |
49 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
50 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
51 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
52 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
53 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
54 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
55 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
56 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
57 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
58 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
59 | * SUCH DAMAGE. | |
60 | * | |
61 | * @(#)uipc_domain.c 8.3 (Berkeley) 2/14/95 | |
62 | */ | |
63 | ||
64 | #include <sys/param.h> | |
65 | #include <sys/socket.h> | |
66 | #include <sys/protosw.h> | |
67 | #include <sys/domain.h> | |
316670eb | 68 | #include <sys/mcache.h> |
1c79356b A |
69 | #include <sys/mbuf.h> |
70 | #include <sys/time.h> | |
71 | #include <sys/kernel.h> | |
72 | #include <sys/systm.h> | |
91447636 | 73 | #include <sys/proc_internal.h> |
1c79356b A |
74 | #include <sys/sysctl.h> |
75 | #include <sys/syslog.h> | |
76 | #include <sys/queue.h> | |
77 | ||
316670eb | 78 | #include <net/dlil.h> |
5ba3f43e | 79 | #include <net/nwk_wq.h> |
316670eb | 80 | |
39236c6e | 81 | #include <mach/boolean.h> |
2d21ac55 A |
82 | #include <pexpert/pexpert.h> |
83 | ||
5ba3f43e A |
84 | /* Eventhandler context for protocol events */ |
85 | struct eventhandler_lists_ctxt protoctl_evhdlr_ctxt; | |
86 | ||
39236c6e A |
87 | static void pr_init_old(struct protosw *, struct domain *); |
88 | static void init_proto(struct protosw *, struct domain *); | |
89 | static void attach_proto(struct protosw *, struct domain *); | |
90 | static void detach_proto(struct protosw *, struct domain *); | |
91 | static void dom_init_old(struct domain *); | |
92 | static void init_domain(struct domain *); | |
93 | static void attach_domain(struct domain *); | |
94 | static void detach_domain(struct domain *); | |
95 | static struct protosw *pffindprotonotype_locked(int, int, int); | |
96 | static struct domain *pffinddomain_locked(int); | |
97 | ||
0a7de745 | 98 | static boolean_t domain_timeout_run; /* domain timer is scheduled to run */ |
39236c6e A |
99 | static boolean_t domain_draining; |
100 | static void domain_sched_timeout(void); | |
101 | static void domain_timeout(void *); | |
102 | ||
0a7de745 A |
103 | lck_grp_t *domain_proto_mtx_grp; |
104 | lck_attr_t *domain_proto_mtx_attr; | |
105 | static lck_grp_attr_t *domain_proto_mtx_grp_attr; | |
316670eb | 106 | decl_lck_mtx_data(static, domain_proto_mtx); |
39236c6e | 107 | decl_lck_mtx_data(static, domain_timeout_mtx); |
1c79356b | 108 | |
5ba3f43e | 109 | u_int64_t _net_uptime; |
cb323159 | 110 | u_int64_t _net_uptime_ms; |
6d2010ae | 111 | |
3e170ce0 A |
112 | #if (DEVELOPMENT || DEBUG) |
113 | ||
114 | SYSCTL_DECL(_kern_ipc); | |
115 | ||
116 | static int sysctl_do_drain_domains SYSCTL_HANDLER_ARGS; | |
117 | ||
118 | SYSCTL_PROC(_kern_ipc, OID_AUTO, do_drain_domains, | |
0a7de745 A |
119 | CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED, |
120 | 0, 0, | |
121 | sysctl_do_drain_domains, "I", "force manual drain domains"); | |
3e170ce0 A |
122 | |
123 | #endif /* DEVELOPMENT || DEBUG */ | |
124 | ||
2d21ac55 | 125 | static void |
39236c6e | 126 | pr_init_old(struct protosw *pp, struct domain *dp) |
2d21ac55 | 127 | { |
39236c6e A |
128 | #pragma unused(dp) |
129 | VERIFY(pp->pr_flags & PR_OLD); | |
130 | VERIFY(pp->pr_old != NULL); | |
2d21ac55 | 131 | |
0a7de745 | 132 | if (pp->pr_old->pr_init != NULL) { |
39236c6e | 133 | pp->pr_old->pr_init(); |
0a7de745 | 134 | } |
2d21ac55 A |
135 | } |
136 | ||
39236c6e A |
137 | static void |
138 | init_proto(struct protosw *pp, struct domain *dp) | |
1c79356b | 139 | { |
39236c6e | 140 | VERIFY(pp->pr_flags & PR_ATTACHED); |
91447636 | 141 | |
39236c6e A |
142 | if (!(pp->pr_flags & PR_INITIALIZED)) { |
143 | TAILQ_INIT(&pp->pr_filter_head); | |
0a7de745 | 144 | if (pp->pr_init != NULL) { |
39236c6e | 145 | pp->pr_init(pp, dp); |
0a7de745 | 146 | } |
39236c6e A |
147 | pp->pr_flags |= PR_INITIALIZED; |
148 | } | |
149 | } | |
1c79356b | 150 | |
39236c6e A |
151 | static void |
152 | attach_proto(struct protosw *pp, struct domain *dp) | |
153 | { | |
154 | domain_proto_mtx_lock_assert_held(); | |
155 | VERIFY(!(pp->pr_flags & PR_ATTACHED)); | |
156 | VERIFY(pp->pr_domain == NULL); | |
157 | VERIFY(pp->pr_protosw == NULL); | |
158 | ||
159 | TAILQ_INSERT_TAIL(&dp->dom_protosw, pp, pr_entry); | |
160 | pp->pr_flags |= PR_ATTACHED; | |
161 | pp->pr_domain = dp; | |
162 | pp->pr_protosw = pp; | |
163 | ||
164 | /* do some cleaning up on user request callbacks */ | |
165 | pru_sanitize(pp->pr_usrreqs); | |
166 | } | |
1c79356b | 167 | |
39236c6e A |
168 | static void |
169 | detach_proto(struct protosw *pp, struct domain *dp) | |
170 | { | |
171 | domain_proto_mtx_lock_assert_held(); | |
172 | VERIFY(pp->pr_flags & PR_ATTACHED); | |
173 | VERIFY(pp->pr_domain == dp); | |
174 | VERIFY(pp->pr_protosw == pp); | |
175 | ||
176 | TAILQ_REMOVE(&dp->dom_protosw, pp, pr_entry); | |
177 | pp->pr_flags &= ~PR_ATTACHED; | |
178 | pp->pr_domain = NULL; | |
179 | pp->pr_protosw = NULL; | |
180 | } | |
1c79356b | 181 | |
39236c6e A |
182 | static void |
183 | dom_init_old(struct domain *dp) | |
184 | { | |
185 | VERIFY(dp->dom_flags & DOM_OLD); | |
186 | VERIFY(dp->dom_old != NULL); | |
6d2010ae | 187 | |
0a7de745 | 188 | if (dp->dom_old->dom_init != NULL) { |
39236c6e | 189 | dp->dom_old->dom_init(); |
0a7de745 | 190 | } |
39236c6e | 191 | } |
2d21ac55 | 192 | |
39236c6e A |
193 | static void |
194 | init_domain(struct domain *dp) | |
195 | { | |
196 | VERIFY(dp->dom_flags & DOM_ATTACHED); | |
197 | ||
198 | if (!(dp->dom_flags & DOM_INITIALIZED)) { | |
199 | lck_mtx_init(&dp->dom_mtx_s, domain_proto_mtx_grp, | |
200 | domain_proto_mtx_attr); | |
201 | dp->dom_mtx = &dp->dom_mtx_s; | |
202 | TAILQ_INIT(&dp->dom_protosw); | |
0a7de745 | 203 | if (dp->dom_init != NULL) { |
39236c6e | 204 | dp->dom_init(dp); |
0a7de745 | 205 | } |
39236c6e | 206 | dp->dom_flags |= DOM_INITIALIZED; |
1c79356b A |
207 | } |
208 | ||
209 | /* Recompute for new protocol */ | |
0a7de745 | 210 | if (_max_linkhdr < 16) { /* XXX - Sheesh; everything's ether? */ |
316670eb | 211 | _max_linkhdr = 16; |
0a7de745 A |
212 | } |
213 | _max_linkhdr = max_linkhdr; /* round it up */ | |
316670eb | 214 | |
0a7de745 | 215 | if (dp->dom_protohdrlen > _max_protohdr) { |
316670eb | 216 | _max_protohdr = dp->dom_protohdrlen; |
0a7de745 A |
217 | } |
218 | _max_protohdr = max_protohdr; /* round it up */ | |
316670eb | 219 | |
1c79356b A |
220 | max_hdr = max_linkhdr + max_protohdr; |
221 | max_datalen = MHLEN - max_hdr; | |
222 | } | |
223 | ||
39236c6e A |
224 | static void |
225 | attach_domain(struct domain *dp) | |
226 | { | |
227 | domain_proto_mtx_lock_assert_held(); | |
228 | VERIFY(!(dp->dom_flags & DOM_ATTACHED)); | |
229 | ||
230 | TAILQ_INSERT_TAIL(&domains, dp, dom_entry); | |
231 | dp->dom_flags |= DOM_ATTACHED; | |
232 | } | |
233 | ||
234 | static void | |
235 | detach_domain(struct domain *dp) | |
236 | { | |
237 | domain_proto_mtx_lock_assert_held(); | |
238 | VERIFY(dp->dom_flags & DOM_ATTACHED); | |
239 | ||
240 | TAILQ_REMOVE(&domains, dp, dom_entry); | |
241 | dp->dom_flags &= ~DOM_ATTACHED; | |
242 | ||
243 | if (dp->dom_flags & DOM_OLD) { | |
244 | struct domain_old *odp = dp->dom_old; | |
245 | ||
246 | VERIFY(odp != NULL); | |
247 | odp->dom_next = NULL; | |
248 | odp->dom_mtx = NULL; | |
249 | } | |
1c79356b A |
250 | } |
251 | ||
39236c6e A |
252 | /* |
253 | * Exported (private) routine, indirection of net_add_domain. | |
254 | */ | |
1c79356b | 255 | void |
39236c6e | 256 | net_add_domain_old(struct domain_old *odp) |
2d21ac55 | 257 | { |
39236c6e A |
258 | struct domain *dp; |
259 | domain_guard_t guard; | |
260 | ||
261 | VERIFY(odp != NULL); | |
262 | ||
263 | guard = domain_guard_deploy(); | |
264 | if ((dp = pffinddomain_locked(odp->dom_family)) != NULL) { | |
265 | /* | |
266 | * There is really nothing better than to panic here, | |
267 | * as the caller would not have been able to handle | |
268 | * any failures otherwise. | |
269 | */ | |
270 | panic("%s: domain (%d,%s) already exists for %s\n", __func__, | |
271 | dp->dom_family, dp->dom_name, odp->dom_name); | |
272 | /* NOTREACHED */ | |
273 | } | |
316670eb | 274 | |
39236c6e A |
275 | /* Make sure nothing is currently pointing to the odp. */ |
276 | TAILQ_FOREACH(dp, &domains, dom_entry) { | |
277 | if (dp->dom_old == odp) { | |
278 | panic("%s: domain %p (%d,%s) is already " | |
279 | "associated with %p (%d,%s)\n", __func__, | |
280 | odp, odp->dom_family, odp->dom_name, dp, | |
281 | dp->dom_family, dp->dom_name); | |
282 | /* NOTREACHED */ | |
283 | } | |
284 | } | |
1c79356b | 285 | |
39236c6e A |
286 | if (odp->dom_protosw != NULL) { |
287 | panic("%s: domain (%d,%s) protocols need to added " | |
288 | "via net_add_proto\n", __func__, odp->dom_family, | |
289 | odp->dom_name); | |
290 | /* NOTREACHED */ | |
291 | } | |
1c79356b | 292 | |
0a7de745 | 293 | dp = _MALLOC(sizeof(*dp), M_TEMP, M_WAITOK | M_ZERO); |
39236c6e A |
294 | if (dp == NULL) { |
295 | /* | |
296 | * There is really nothing better than to panic here, | |
297 | * as the caller would not have been able to handle | |
298 | * any failures otherwise. | |
299 | */ | |
300 | panic("%s: unable to allocate memory for domain family " | |
301 | "%d (%s)\n", __func__, odp->dom_family, odp->dom_name); | |
302 | /* NOTREACHED */ | |
303 | } | |
304 | ||
305 | /* Copy everything but dom_init, dom_mtx, dom_next and dom_refs */ | |
0a7de745 A |
306 | dp->dom_family = odp->dom_family; |
307 | dp->dom_flags = (odp->dom_flags & DOMF_USERFLAGS) | DOM_OLD; | |
308 | dp->dom_name = odp->dom_name; | |
309 | dp->dom_init = dom_init_old; | |
310 | dp->dom_externalize = odp->dom_externalize; | |
311 | dp->dom_dispose = odp->dom_dispose; | |
312 | dp->dom_rtattach = odp->dom_rtattach; | |
313 | dp->dom_rtoffset = odp->dom_rtoffset; | |
314 | dp->dom_maxrtkey = odp->dom_maxrtkey; | |
315 | dp->dom_protohdrlen = odp->dom_protohdrlen; | |
316 | dp->dom_old = odp; | |
39236c6e A |
317 | |
318 | attach_domain(dp); | |
1c79356b A |
319 | init_domain(dp); |
320 | ||
39236c6e | 321 | /* Point the mutex back to the internal structure's */ |
0a7de745 | 322 | odp->dom_mtx = dp->dom_mtx; |
39236c6e | 323 | domain_guard_release(guard); |
1c79356b A |
324 | } |
325 | ||
39236c6e A |
326 | /* |
327 | * Exported (private) routine, indirection of net_del_domain. | |
328 | */ | |
1c79356b | 329 | int |
39236c6e A |
330 | net_del_domain_old(struct domain_old *odp) |
331 | { | |
332 | struct domain *dp1, *dp2; | |
333 | int error = 0; | |
334 | domain_guard_t guard; | |
335 | ||
336 | VERIFY(odp != NULL); | |
337 | ||
338 | guard = domain_guard_deploy(); | |
339 | if (odp->dom_refs != 0) { | |
340 | error = EBUSY; | |
341 | goto done; | |
342 | } | |
343 | ||
344 | TAILQ_FOREACH_SAFE(dp1, &domains, dom_entry, dp2) { | |
0a7de745 | 345 | if (!(dp1->dom_flags & DOM_OLD)) { |
39236c6e | 346 | continue; |
0a7de745 | 347 | } |
39236c6e | 348 | VERIFY(dp1->dom_old != NULL); |
0a7de745 | 349 | if (odp == dp1->dom_old) { |
1c79356b | 350 | break; |
0a7de745 | 351 | } |
1c79356b | 352 | } |
39236c6e A |
353 | if (dp1 != NULL) { |
354 | struct protosw *pp1, *pp2; | |
355 | ||
356 | VERIFY(dp1->dom_flags & DOM_OLD); | |
357 | VERIFY(dp1->dom_old == odp); | |
358 | ||
359 | /* Remove all protocols attached to this domain */ | |
360 | TAILQ_FOREACH_SAFE(pp1, &dp1->dom_protosw, pr_entry, pp2) { | |
361 | detach_proto(pp1, dp1); | |
0a7de745 | 362 | if (pp1->pr_usrreqs->pru_flags & PRUF_OLD) { |
39236c6e | 363 | FREE(pp1->pr_usrreqs, M_TEMP); |
0a7de745 A |
364 | } |
365 | if (pp1->pr_flags & PR_OLD) { | |
39236c6e | 366 | FREE(pp1, M_TEMP); |
0a7de745 | 367 | } |
39236c6e | 368 | } |
1c79356b | 369 | |
39236c6e A |
370 | detach_domain(dp1); |
371 | FREE(dp1, M_TEMP); | |
372 | } else { | |
373 | error = EPFNOSUPPORT; | |
374 | } | |
375 | done: | |
376 | domain_guard_release(guard); | |
0a7de745 | 377 | return error; |
1c79356b A |
378 | } |
379 | ||
380 | /* | |
39236c6e A |
381 | * Internal routine, not exported. |
382 | * | |
1c79356b | 383 | * net_add_proto - link a protosw into a domain's protosw chain |
39236c6e A |
384 | * |
385 | * NOTE: Caller must have acquired domain_proto_mtx | |
386 | */ | |
387 | int | |
388 | net_add_proto(struct protosw *pp, struct domain *dp, int doinit) | |
389 | { | |
390 | struct protosw *pp1; | |
391 | ||
392 | /* | |
393 | * This could be called as part of initializing the domain, | |
394 | * and thus DOM_INITIALIZED may not be set (yet). | |
395 | */ | |
396 | domain_proto_mtx_lock_assert_held(); | |
397 | VERIFY(!(pp->pr_flags & PR_ATTACHED)); | |
398 | ||
399 | /* pr_domain is set only after the protocol is attached */ | |
400 | if (pp->pr_domain != NULL) { | |
401 | panic("%s: domain (%d,%s), proto %d has non-NULL pr_domain!\n", | |
402 | __func__, dp->dom_family, dp->dom_name, pp->pr_protocol); | |
403 | /* NOTREACHED */ | |
404 | } | |
405 | ||
406 | if (pp->pr_usrreqs == NULL) { | |
407 | panic("%s: domain (%d,%s), proto %d has no usrreqs!\n", | |
408 | __func__, dp->dom_family, dp->dom_name, pp->pr_protocol); | |
409 | /* NOTREACHED */ | |
410 | } | |
411 | ||
412 | TAILQ_FOREACH(pp1, &dp->dom_protosw, pr_entry) { | |
413 | if (pp1->pr_type == pp->pr_type && | |
0a7de745 A |
414 | pp1->pr_protocol == pp->pr_protocol) { |
415 | return EEXIST; | |
416 | } | |
39236c6e A |
417 | } |
418 | ||
419 | attach_proto(pp, dp); | |
0a7de745 | 420 | if (doinit) { |
39236c6e | 421 | net_init_proto(pp, dp); |
0a7de745 | 422 | } |
39236c6e | 423 | |
0a7de745 | 424 | return 0; |
39236c6e A |
425 | } |
426 | ||
427 | void | |
428 | net_init_proto(struct protosw *pp, struct domain *dp) | |
429 | { | |
430 | /* | |
431 | * This could be called as part of initializing the domain, | |
432 | * and thus DOM_INITIALIZED may not be set (yet). The protocol | |
433 | * must have been attached via net_addr_protosw() by now. | |
434 | */ | |
435 | domain_proto_mtx_lock_assert_held(); | |
436 | VERIFY(pp->pr_flags & PR_ATTACHED); | |
437 | ||
438 | init_proto(pp, dp); | |
439 | } | |
440 | ||
441 | /* | |
442 | * Exported (private) routine, indirection of net_add_proto. | |
1c79356b A |
443 | */ |
444 | int | |
39236c6e A |
445 | net_add_proto_old(struct protosw_old *opp, struct domain_old *odp) |
446 | { | |
447 | struct pr_usrreqs_old *opru; | |
448 | struct pr_usrreqs *pru = NULL; | |
449 | struct protosw *pp = NULL, *pp1; | |
450 | int error = 0; | |
451 | struct domain *dp; | |
452 | domain_guard_t guard; | |
453 | ||
454 | /* | |
455 | * This could be called as part of initializing the domain, | |
456 | * and thus DOM_INITIALIZED may not be set (yet). | |
457 | */ | |
458 | guard = domain_guard_deploy(); | |
459 | ||
460 | /* Make sure the domain has been added via net_add_domain */ | |
461 | TAILQ_FOREACH(dp, &domains, dom_entry) { | |
0a7de745 | 462 | if (!(dp->dom_flags & DOM_OLD)) { |
39236c6e | 463 | continue; |
0a7de745 A |
464 | } |
465 | if (dp->dom_old == odp) { | |
39236c6e | 466 | break; |
0a7de745 | 467 | } |
39236c6e A |
468 | } |
469 | if (dp == NULL) { | |
470 | error = EINVAL; | |
471 | goto done; | |
472 | } | |
1c79356b | 473 | |
39236c6e A |
474 | TAILQ_FOREACH(pp1, &dp->dom_protosw, pr_entry) { |
475 | if (pp1->pr_type == opp->pr_type && | |
476 | pp1->pr_protocol == opp->pr_protocol) { | |
477 | error = EEXIST; | |
478 | goto done; | |
1c79356b | 479 | } |
1c79356b | 480 | } |
1c79356b | 481 | |
39236c6e A |
482 | if ((opru = opp->pr_usrreqs) == NULL) { |
483 | panic("%s: domain (%d,%s), proto %d has no usrreqs!\n", | |
484 | __func__, odp->dom_family, odp->dom_name, opp->pr_protocol); | |
485 | /* NOTREACHED */ | |
486 | } | |
2d21ac55 | 487 | |
0a7de745 | 488 | pru = _MALLOC(sizeof(*pru), M_TEMP, M_WAITOK | M_ZERO); |
39236c6e A |
489 | if (pru == NULL) { |
490 | error = ENOMEM; | |
491 | goto done; | |
492 | } | |
493 | ||
0a7de745 A |
494 | pru->pru_flags = PRUF_OLD; |
495 | pru->pru_abort = opru->pru_abort; | |
496 | pru->pru_accept = opru->pru_accept; | |
497 | pru->pru_attach = opru->pru_attach; | |
498 | pru->pru_bind = opru->pru_bind; | |
499 | pru->pru_connect = opru->pru_connect; | |
500 | pru->pru_connect2 = opru->pru_connect2; | |
501 | pru->pru_control = opru->pru_control; | |
502 | pru->pru_detach = opru->pru_detach; | |
503 | pru->pru_disconnect = opru->pru_disconnect; | |
504 | pru->pru_listen = opru->pru_listen; | |
505 | pru->pru_peeraddr = opru->pru_peeraddr; | |
506 | pru->pru_rcvd = opru->pru_rcvd; | |
507 | pru->pru_rcvoob = opru->pru_rcvoob; | |
508 | pru->pru_send = opru->pru_send; | |
509 | pru->pru_sense = opru->pru_sense; | |
510 | pru->pru_shutdown = opru->pru_shutdown; | |
511 | pru->pru_sockaddr = opru->pru_sockaddr; | |
512 | pru->pru_sosend = opru->pru_sosend; | |
513 | pru->pru_soreceive = opru->pru_soreceive; | |
514 | pru->pru_sopoll = opru->pru_sopoll; | |
515 | ||
516 | pp = _MALLOC(sizeof(*pp), M_TEMP, M_WAITOK | M_ZERO); | |
39236c6e A |
517 | if (pp == NULL) { |
518 | error = ENOMEM; | |
519 | goto done; | |
520 | } | |
521 | ||
522 | /* | |
523 | * Protocol fast and slow timers are now deprecated. | |
524 | */ | |
525 | if (opp->pr_unused != NULL) { | |
526 | printf("%s: domain (%d,%s), proto %d: pr_fasttimo is " | |
527 | "deprecated and won't be called\n", __func__, | |
528 | odp->dom_family, odp->dom_name, opp->pr_protocol); | |
529 | } | |
530 | if (opp->pr_unused2 != NULL) { | |
531 | printf("%s: domain (%d,%s), proto %d: pr_slowtimo is " | |
532 | "deprecated and won't be called\n", __func__, | |
533 | odp->dom_family, odp->dom_name, opp->pr_protocol); | |
534 | } | |
535 | ||
536 | /* Copy everything but pr_init, pr_next, pr_domain, pr_protosw */ | |
0a7de745 A |
537 | pp->pr_type = opp->pr_type; |
538 | pp->pr_protocol = opp->pr_protocol; | |
539 | pp->pr_flags = (opp->pr_flags & PRF_USERFLAGS) | PR_OLD; | |
540 | pp->pr_input = opp->pr_input; | |
541 | pp->pr_output = opp->pr_output; | |
542 | pp->pr_ctlinput = opp->pr_ctlinput; | |
543 | pp->pr_ctloutput = opp->pr_ctloutput; | |
544 | pp->pr_usrreqs = pru; | |
545 | pp->pr_init = pr_init_old; | |
546 | pp->pr_drain = opp->pr_drain; | |
547 | pp->pr_sysctl = opp->pr_sysctl; | |
548 | pp->pr_lock = opp->pr_lock; | |
549 | pp->pr_unlock = opp->pr_unlock; | |
550 | pp->pr_getlock = opp->pr_getlock; | |
551 | pp->pr_old = opp; | |
39236c6e A |
552 | |
553 | /* attach as well as initialize */ | |
554 | attach_proto(pp, dp); | |
555 | net_init_proto(pp, dp); | |
556 | done: | |
557 | if (error != 0) { | |
558 | printf("%s: domain (%d,%s), proto %d: failed to attach, " | |
559 | "error %d\n", __func__, odp->dom_family, | |
560 | odp->dom_name, opp->pr_protocol, error); | |
561 | ||
0a7de745 | 562 | if (pru != NULL) { |
39236c6e | 563 | FREE(pru, M_TEMP); |
0a7de745 A |
564 | } |
565 | if (pp != NULL) { | |
39236c6e | 566 | FREE(pp, M_TEMP); |
0a7de745 | 567 | } |
39236c6e A |
568 | } |
569 | ||
570 | domain_guard_release(guard); | |
0a7de745 | 571 | return error; |
1c79356b A |
572 | } |
573 | ||
574 | /* | |
39236c6e A |
575 | * Internal routine, not exported. |
576 | * | |
1c79356b A |
577 | * net_del_proto - remove a protosw from a domain's protosw chain. |
578 | * Search the protosw chain for the element with matching data. | |
579 | * Then unlink and return. | |
91447636 | 580 | * |
39236c6e | 581 | * NOTE: Caller must have acquired domain_proto_mtx |
1c79356b A |
582 | */ |
583 | int | |
2d21ac55 A |
584 | net_del_proto(int type, int protocol, struct domain *dp) |
585 | { | |
39236c6e A |
586 | struct protosw *pp; |
587 | ||
588 | /* | |
589 | * This could be called as part of initializing the domain, | |
590 | * and thus DOM_INITIALIZED may not be set (yet). | |
591 | */ | |
592 | domain_proto_mtx_lock_assert_held(); | |
1c79356b | 593 | |
39236c6e | 594 | TAILQ_FOREACH(pp, &dp->dom_protosw, pr_entry) { |
0a7de745 | 595 | if (pp->pr_type == type && pp->pr_protocol == protocol) { |
1c79356b | 596 | break; |
0a7de745 A |
597 | } |
598 | } | |
599 | if (pp == NULL) { | |
600 | return ENXIO; | |
1c79356b | 601 | } |
39236c6e A |
602 | |
603 | detach_proto(pp, dp); | |
0a7de745 | 604 | if (pp->pr_usrreqs->pru_flags & PRUF_OLD) { |
39236c6e | 605 | FREE(pp->pr_usrreqs, M_TEMP); |
0a7de745 A |
606 | } |
607 | if (pp->pr_flags & PR_OLD) { | |
39236c6e | 608 | FREE(pp, M_TEMP); |
0a7de745 | 609 | } |
39236c6e | 610 | |
0a7de745 | 611 | return 0; |
1c79356b A |
612 | } |
613 | ||
39236c6e A |
614 | /* |
615 | * Exported (private) routine, indirection of net_del_proto. | |
616 | */ | |
617 | int | |
618 | net_del_proto_old(int type, int protocol, struct domain_old *odp) | |
619 | { | |
620 | int error = 0; | |
621 | struct protosw *pp; | |
622 | struct domain *dp; | |
623 | domain_guard_t guard; | |
1c79356b | 624 | |
39236c6e A |
625 | /* |
626 | * This could be called as part of initializing the domain, | |
627 | * and thus DOM_INITIALIZED may not be set (yet). | |
628 | */ | |
629 | guard = domain_guard_deploy(); | |
630 | ||
631 | /* Make sure the domain has been added via net_add_domain */ | |
632 | TAILQ_FOREACH(dp, &domains, dom_entry) { | |
0a7de745 | 633 | if (!(dp->dom_flags & DOM_OLD)) { |
39236c6e | 634 | continue; |
0a7de745 A |
635 | } |
636 | if (dp->dom_old == odp) { | |
39236c6e | 637 | break; |
0a7de745 | 638 | } |
39236c6e A |
639 | } |
640 | if (dp == NULL) { | |
641 | error = ENXIO; | |
642 | goto done; | |
643 | } | |
644 | ||
645 | TAILQ_FOREACH(pp, &dp->dom_protosw, pr_entry) { | |
0a7de745 | 646 | if (pp->pr_type == type && pp->pr_protocol == protocol) { |
39236c6e | 647 | break; |
0a7de745 | 648 | } |
39236c6e A |
649 | } |
650 | if (pp == NULL) { | |
651 | error = ENXIO; | |
652 | goto done; | |
653 | } | |
654 | detach_proto(pp, dp); | |
0a7de745 | 655 | if (pp->pr_usrreqs->pru_flags & PRUF_OLD) { |
39236c6e | 656 | FREE(pp->pr_usrreqs, M_TEMP); |
0a7de745 A |
657 | } |
658 | if (pp->pr_flags & PR_OLD) { | |
39236c6e | 659 | FREE(pp, M_TEMP); |
0a7de745 | 660 | } |
39236c6e A |
661 | |
662 | done: | |
663 | domain_guard_release(guard); | |
0a7de745 | 664 | return error; |
39236c6e A |
665 | } |
666 | ||
667 | static void | |
668 | domain_sched_timeout(void) | |
669 | { | |
5ba3f43e | 670 | LCK_MTX_ASSERT(&domain_timeout_mtx, LCK_MTX_ASSERT_OWNED); |
39236c6e A |
671 | |
672 | if (!domain_timeout_run && domain_draining) { | |
673 | domain_timeout_run = TRUE; | |
674 | timeout(domain_timeout, NULL, hz); | |
675 | } | |
676 | } | |
677 | ||
678 | void | |
679 | net_drain_domains(void) | |
680 | { | |
681 | lck_mtx_lock(&domain_timeout_mtx); | |
682 | domain_draining = TRUE; | |
683 | domain_sched_timeout(); | |
684 | lck_mtx_unlock(&domain_timeout_mtx); | |
685 | } | |
1c79356b | 686 | |
1c79356b | 687 | #if INET6 |
39236c6e | 688 | extern struct domain inet6domain_s; |
1c79356b A |
689 | #endif |
690 | #if IPSEC | |
39236c6e | 691 | extern struct domain keydomain_s; |
1c79356b A |
692 | #endif |
693 | ||
39236c6e A |
694 | extern struct domain routedomain_s, ndrvdomain_s, inetdomain_s; |
695 | extern struct domain systemdomain_s, localdomain_s; | |
696 | ||
697 | #if MULTIPATH | |
698 | extern struct domain mpdomain_s; | |
699 | #endif /* MULTIPATH */ | |
700 | ||
701 | static void | |
702 | domain_timeout(void *arg) | |
703 | { | |
704 | #pragma unused(arg) | |
705 | struct protosw *pp; | |
706 | struct domain *dp; | |
707 | domain_guard_t guard; | |
708 | ||
709 | lck_mtx_lock(&domain_timeout_mtx); | |
710 | if (domain_draining) { | |
711 | domain_draining = FALSE; | |
712 | lck_mtx_unlock(&domain_timeout_mtx); | |
713 | ||
714 | guard = domain_guard_deploy(); | |
715 | TAILQ_FOREACH(dp, &domains, dom_entry) { | |
716 | TAILQ_FOREACH(pp, &dp->dom_protosw, pr_entry) { | |
0a7de745 | 717 | if (pp->pr_drain != NULL) { |
39236c6e | 718 | (*pp->pr_drain)(); |
0a7de745 | 719 | } |
39236c6e A |
720 | } |
721 | } | |
722 | domain_guard_release(guard); | |
723 | ||
724 | lck_mtx_lock(&domain_timeout_mtx); | |
725 | } | |
726 | ||
727 | /* re-arm the timer if there's work to do */ | |
728 | domain_timeout_run = FALSE; | |
729 | domain_sched_timeout(); | |
730 | lck_mtx_unlock(&domain_timeout_mtx); | |
731 | } | |
2d21ac55 A |
732 | |
733 | void | |
734 | domaininit(void) | |
735 | { | |
39236c6e A |
736 | struct domain *dp; |
737 | domain_guard_t guard; | |
2d21ac55 | 738 | |
5ba3f43e | 739 | eventhandler_lists_ctxt_init(&protoctl_evhdlr_ctxt); |
91447636 A |
740 | /* |
741 | * allocate lock group attribute and group for domain mutexes | |
742 | */ | |
743 | domain_proto_mtx_grp_attr = lck_grp_attr_alloc_init(); | |
91447636 | 744 | |
39236c6e A |
745 | domain_proto_mtx_grp = lck_grp_alloc_init("domain", |
746 | domain_proto_mtx_grp_attr); | |
747 | ||
91447636 A |
748 | /* |
749 | * allocate the lock attribute for per domain mutexes | |
750 | */ | |
751 | domain_proto_mtx_attr = lck_attr_alloc_init(); | |
91447636 | 752 | |
316670eb | 753 | lck_mtx_init(&domain_proto_mtx, domain_proto_mtx_grp, |
39236c6e A |
754 | domain_proto_mtx_attr); |
755 | lck_mtx_init(&domain_timeout_mtx, domain_proto_mtx_grp, | |
756 | domain_proto_mtx_attr); | |
757 | ||
758 | guard = domain_guard_deploy(); | |
1c79356b | 759 | /* |
39236c6e A |
760 | * Add all the static domains to the domains list. route domain |
761 | * gets added and initialized last, since we need it to attach | |
762 | * rt_tables[] to everything that's already there. This also | |
763 | * means that domains added after this point won't get their | |
764 | * dom_rtattach() called on rt_tables[]. | |
1c79356b | 765 | */ |
39236c6e | 766 | attach_domain(&inetdomain_s); |
1c79356b | 767 | #if INET6 |
39236c6e A |
768 | attach_domain(&inet6domain_s); |
769 | #endif /* INET6 */ | |
770 | #if MULTIPATH | |
771 | attach_domain(&mpdomain_s); | |
772 | #endif /* MULTIPATH */ | |
773 | attach_domain(&systemdomain_s); | |
774 | attach_domain(&localdomain_s); | |
1c79356b | 775 | #if IPSEC |
39236c6e A |
776 | attach_domain(&keydomain_s); |
777 | #endif /* IPSEC */ | |
778 | attach_domain(&ndrvdomain_s); | |
0a7de745 | 779 | attach_domain(&routedomain_s); /* must be last domain */ |
1c79356b A |
780 | |
781 | /* | |
782 | * Now ask them all to init (XXX including the routing domain, | |
783 | * see above) | |
784 | */ | |
39236c6e | 785 | TAILQ_FOREACH(dp, &domains, dom_entry) |
0a7de745 | 786 | init_domain(dp); |
1c79356b | 787 | |
39236c6e | 788 | domain_guard_release(guard); |
1c79356b A |
789 | } |
790 | ||
2d21ac55 A |
791 | static __inline__ struct domain * |
792 | pffinddomain_locked(int pf) | |
793 | { | |
794 | struct domain *dp; | |
795 | ||
39236c6e A |
796 | domain_proto_mtx_lock_assert_held(); |
797 | ||
798 | TAILQ_FOREACH(dp, &domains, dom_entry) { | |
0a7de745 | 799 | if (dp->dom_family == pf) { |
2d21ac55 | 800 | break; |
0a7de745 | 801 | } |
2d21ac55 | 802 | } |
0a7de745 | 803 | return dp; |
2d21ac55 A |
804 | } |
805 | ||
1c79356b | 806 | struct protosw * |
2d21ac55 | 807 | pffindtype(int family, int type) |
1c79356b | 808 | { |
39236c6e A |
809 | struct protosw *pp = NULL; |
810 | struct domain *dp; | |
811 | domain_guard_t guard; | |
1c79356b | 812 | |
39236c6e | 813 | guard = domain_guard_deploy(); |
0a7de745 | 814 | if ((dp = pffinddomain_locked(family)) == NULL) { |
39236c6e | 815 | goto done; |
0a7de745 | 816 | } |
39236c6e A |
817 | |
818 | TAILQ_FOREACH(pp, &dp->dom_protosw, pr_entry) { | |
0a7de745 | 819 | if (pp->pr_type != 0 && pp->pr_type == type) { |
39236c6e | 820 | goto done; |
0a7de745 | 821 | } |
2d21ac55 | 822 | } |
39236c6e A |
823 | done: |
824 | domain_guard_release(guard); | |
0a7de745 | 825 | return pp; |
1c79356b A |
826 | } |
827 | ||
39236c6e A |
828 | /* |
829 | * Internal routine, not exported. | |
830 | */ | |
1c79356b A |
831 | struct domain * |
832 | pffinddomain(int pf) | |
2d21ac55 A |
833 | { |
834 | struct domain *dp; | |
39236c6e | 835 | domain_guard_t guard; |
1c79356b | 836 | |
39236c6e | 837 | guard = domain_guard_deploy(); |
2d21ac55 | 838 | dp = pffinddomain_locked(pf); |
39236c6e | 839 | domain_guard_release(guard); |
0a7de745 | 840 | return dp; |
39236c6e A |
841 | } |
842 | ||
843 | /* | |
844 | * Exported (private) routine, indirection of pffinddomain. | |
845 | */ | |
846 | struct domain_old * | |
847 | pffinddomain_old(int pf) | |
848 | { | |
849 | struct domain_old *odp = NULL; | |
850 | struct domain *dp; | |
851 | domain_guard_t guard; | |
852 | ||
853 | guard = domain_guard_deploy(); | |
0a7de745 | 854 | if ((dp = pffinddomain_locked(pf)) != NULL && (dp->dom_flags & DOM_OLD)) { |
39236c6e | 855 | odp = dp->dom_old; |
0a7de745 | 856 | } |
39236c6e | 857 | domain_guard_release(guard); |
0a7de745 | 858 | return odp; |
316670eb | 859 | } |
1c79356b | 860 | |
39236c6e A |
861 | /* |
862 | * Internal routine, not exported. | |
863 | */ | |
1c79356b | 864 | struct protosw * |
2d21ac55 | 865 | pffindproto(int family, int protocol, int type) |
91447636 | 866 | { |
39236c6e A |
867 | struct protosw *pp; |
868 | domain_guard_t guard; | |
869 | ||
870 | guard = domain_guard_deploy(); | |
871 | pp = pffindproto_locked(family, protocol, type); | |
872 | domain_guard_release(guard); | |
0a7de745 | 873 | return pp; |
91447636 A |
874 | } |
875 | ||
876 | struct protosw * | |
2d21ac55 | 877 | pffindproto_locked(int family, int protocol, int type) |
1c79356b | 878 | { |
39236c6e A |
879 | struct protosw *maybe = NULL; |
880 | struct protosw *pp; | |
881 | struct domain *dp; | |
882 | ||
883 | domain_proto_mtx_lock_assert_held(); | |
1c79356b | 884 | |
0a7de745 A |
885 | if (family == 0) { |
886 | return 0; | |
887 | } | |
39236c6e | 888 | |
2d21ac55 | 889 | dp = pffinddomain_locked(family); |
0a7de745 A |
890 | if (dp == NULL) { |
891 | return NULL; | |
892 | } | |
1c79356b | 893 | |
39236c6e | 894 | TAILQ_FOREACH(pp, &dp->dom_protosw, pr_entry) { |
0a7de745 A |
895 | if ((pp->pr_protocol == protocol) && (pp->pr_type == type)) { |
896 | return pp; | |
897 | } | |
39236c6e A |
898 | |
899 | if (type == SOCK_RAW && pp->pr_type == SOCK_RAW && | |
0a7de745 | 900 | pp->pr_protocol == 0 && maybe == NULL) { |
39236c6e | 901 | maybe = pp; |
0a7de745 | 902 | } |
1c79356b | 903 | } |
0a7de745 | 904 | return maybe; |
1c79356b A |
905 | } |
906 | ||
39236c6e A |
907 | /* |
908 | * Exported (private) routine, indirection of pffindproto. | |
909 | */ | |
910 | struct protosw_old * | |
911 | pffindproto_old(int family, int protocol, int type) | |
912 | { | |
913 | struct protosw_old *opr = NULL; | |
914 | struct protosw *pp; | |
915 | domain_guard_t guard; | |
916 | ||
917 | guard = domain_guard_deploy(); | |
918 | if ((pp = pffindproto_locked(family, protocol, type)) != NULL && | |
0a7de745 | 919 | (pp->pr_flags & PR_OLD)) { |
39236c6e | 920 | opr = pp->pr_old; |
0a7de745 | 921 | } |
39236c6e | 922 | domain_guard_release(guard); |
0a7de745 | 923 | return opr; |
39236c6e A |
924 | } |
925 | ||
926 | static struct protosw * | |
927 | pffindprotonotype_locked(int family, int protocol, int type) | |
2d21ac55 | 928 | { |
39236c6e A |
929 | #pragma unused(type) |
930 | struct domain *dp; | |
931 | struct protosw *pp; | |
932 | ||
933 | domain_proto_mtx_lock_assert_held(); | |
2d21ac55 | 934 | |
0a7de745 A |
935 | if (family == 0) { |
936 | return 0; | |
937 | } | |
39236c6e | 938 | |
2d21ac55 | 939 | dp = pffinddomain_locked(family); |
0a7de745 A |
940 | if (dp == NULL) { |
941 | return NULL; | |
942 | } | |
39236c6e A |
943 | |
944 | TAILQ_FOREACH(pp, &dp->dom_protosw, pr_entry) { | |
0a7de745 A |
945 | if (pp->pr_protocol == protocol) { |
946 | return pp; | |
947 | } | |
2d21ac55 | 948 | } |
0a7de745 | 949 | return NULL; |
2d21ac55 A |
950 | } |
951 | ||
952 | struct protosw * | |
953 | pffindprotonotype(int family, int protocol) | |
954 | { | |
39236c6e A |
955 | struct protosw *pp; |
956 | domain_guard_t guard; | |
957 | ||
0a7de745 A |
958 | if (protocol == 0) { |
959 | return NULL; | |
960 | } | |
39236c6e A |
961 | |
962 | guard = domain_guard_deploy(); | |
963 | pp = pffindprotonotype_locked(family, protocol, 0); | |
964 | domain_guard_release(guard); | |
0a7de745 | 965 | return pp; |
2d21ac55 A |
966 | } |
967 | ||
1c79356b | 968 | void |
2d21ac55 | 969 | pfctlinput(int cmd, struct sockaddr *sa) |
1c79356b | 970 | { |
39236c6e | 971 | pfctlinput2(cmd, sa, NULL); |
9bccf70c A |
972 | } |
973 | ||
974 | void | |
2d21ac55 | 975 | pfctlinput2(int cmd, struct sockaddr *sa, void *ctlparam) |
9bccf70c A |
976 | { |
977 | struct domain *dp; | |
39236c6e A |
978 | struct protosw *pp; |
979 | domain_guard_t guard; | |
1c79356b | 980 | |
0a7de745 | 981 | if (sa == NULL) { |
9bccf70c | 982 | return; |
0a7de745 | 983 | } |
91447636 | 984 | |
39236c6e A |
985 | guard = domain_guard_deploy(); |
986 | TAILQ_FOREACH(dp, &domains, dom_entry) { | |
987 | TAILQ_FOREACH(pp, &dp->dom_protosw, pr_entry) { | |
0a7de745 | 988 | if (pp->pr_ctlinput != NULL) { |
5ba3f43e | 989 | (*pp->pr_ctlinput)(cmd, sa, ctlparam, NULL); |
0a7de745 | 990 | } |
39236c6e A |
991 | } |
992 | } | |
993 | domain_guard_release(guard); | |
1c79356b A |
994 | } |
995 | ||
996 | void | |
5ba3f43e | 997 | net_update_uptime_with_time(const struct timeval *tvp) |
1c79356b | 998 | { |
5ba3f43e | 999 | _net_uptime = tvp->tv_sec; |
6d2010ae | 1000 | /* |
39236c6e A |
1001 | * Round up the timer to the nearest integer value because otherwise |
1002 | * we might setup networking timers that are off by almost 1 second. | |
6d2010ae | 1003 | */ |
0a7de745 | 1004 | if (tvp->tv_usec > 500000) { |
39236c6e | 1005 | _net_uptime++; |
0a7de745 | 1006 | } |
cb323159 A |
1007 | |
1008 | /* update milliseconds variant */ | |
1009 | _net_uptime_ms = (((u_int64_t)tvp->tv_sec * 1000) + | |
1010 | ((u_int64_t)tvp->tv_usec / 1000)); | |
1c79356b A |
1011 | } |
1012 | ||
39236c6e | 1013 | void |
5ba3f43e | 1014 | net_update_uptime(void) |
1c79356b | 1015 | { |
5ba3f43e A |
1016 | struct timeval tv; |
1017 | ||
1018 | microuptime(&tv); | |
1019 | ||
1020 | net_update_uptime_with_time(&tv); | |
39236c6e | 1021 | } |
1c79356b | 1022 | |
39236c6e A |
1023 | /* |
1024 | * Convert our uin64_t net_uptime to a struct timeval. | |
1025 | */ | |
1026 | void | |
1027 | net_uptime2timeval(struct timeval *tv) | |
1028 | { | |
0a7de745 | 1029 | if (tv == NULL) { |
39236c6e | 1030 | return; |
0a7de745 | 1031 | } |
39236c6e A |
1032 | |
1033 | tv->tv_usec = 0; | |
1034 | tv->tv_sec = net_uptime(); | |
6d2010ae A |
1035 | } |
1036 | ||
1037 | /* | |
1038 | * An alternative way to obtain the coarse-grained uptime (in seconds) | |
1039 | * for networking code which do not require high-precision timestamp, | |
1040 | * as this is significantly cheaper than microuptime(). | |
1041 | */ | |
1042 | u_int64_t | |
1043 | net_uptime(void) | |
1044 | { | |
0a7de745 | 1045 | if (_net_uptime == 0) { |
6d2010ae | 1046 | net_update_uptime(); |
0a7de745 | 1047 | } |
6d2010ae | 1048 | |
0a7de745 | 1049 | return _net_uptime; |
316670eb A |
1050 | } |
1051 | ||
cb323159 A |
1052 | u_int64_t |
1053 | net_uptime_ms(void) | |
1054 | { | |
1055 | if (_net_uptime_ms == 0) { | |
1056 | net_update_uptime(); | |
1057 | } | |
1058 | ||
1059 | return _net_uptime_ms; | |
1060 | } | |
1061 | ||
39236c6e A |
1062 | void |
1063 | domain_proto_mtx_lock_assert_held(void) | |
1064 | { | |
5ba3f43e | 1065 | LCK_MTX_ASSERT(&domain_proto_mtx, LCK_MTX_ASSERT_OWNED); |
39236c6e A |
1066 | } |
1067 | ||
1068 | void | |
1069 | domain_proto_mtx_lock_assert_notheld(void) | |
1070 | { | |
5ba3f43e | 1071 | LCK_MTX_ASSERT(&domain_proto_mtx, LCK_MTX_ASSERT_NOTOWNED); |
39236c6e A |
1072 | } |
1073 | ||
1074 | domain_guard_t | |
1075 | domain_guard_deploy(void) | |
316670eb | 1076 | { |
39236c6e A |
1077 | net_thread_marks_t marks; |
1078 | ||
1079 | marks = net_thread_marks_push(NET_THREAD_HELD_DOMAIN); | |
1080 | if (marks != net_thread_marks_none) { | |
5ba3f43e | 1081 | LCK_MTX_ASSERT(&domain_proto_mtx, LCK_MTX_ASSERT_NOTOWNED); |
316670eb | 1082 | lck_mtx_lock(&domain_proto_mtx); |
0a7de745 | 1083 | } else { |
5ba3f43e | 1084 | LCK_MTX_ASSERT(&domain_proto_mtx, LCK_MTX_ASSERT_OWNED); |
0a7de745 | 1085 | } |
39236c6e | 1086 | |
0a7de745 | 1087 | return (domain_guard_t)(const void*)marks; |
316670eb A |
1088 | } |
1089 | ||
1090 | void | |
39236c6e | 1091 | domain_guard_release(domain_guard_t guard) |
316670eb | 1092 | { |
39236c6e A |
1093 | net_thread_marks_t marks = (net_thread_marks_t)(const void*)guard; |
1094 | ||
1095 | if (marks != net_thread_marks_none) { | |
5ba3f43e | 1096 | LCK_MTX_ASSERT(&domain_proto_mtx, LCK_MTX_ASSERT_OWNED); |
316670eb | 1097 | lck_mtx_unlock(&domain_proto_mtx); |
39236c6e | 1098 | net_thread_marks_pop(marks); |
0a7de745 | 1099 | } else { |
5ba3f43e | 1100 | LCK_MTX_ASSERT(&domain_proto_mtx, LCK_MTX_ASSERT_NOTOWNED); |
0a7de745 | 1101 | } |
39236c6e A |
1102 | } |
1103 | ||
1104 | domain_unguard_t | |
1105 | domain_unguard_deploy(void) | |
1106 | { | |
1107 | net_thread_marks_t marks; | |
1108 | ||
1109 | marks = net_thread_unmarks_push(NET_THREAD_HELD_DOMAIN); | |
1110 | if (marks != net_thread_marks_none) { | |
5ba3f43e | 1111 | LCK_MTX_ASSERT(&domain_proto_mtx, LCK_MTX_ASSERT_OWNED); |
39236c6e | 1112 | lck_mtx_unlock(&domain_proto_mtx); |
0a7de745 | 1113 | } else { |
5ba3f43e | 1114 | LCK_MTX_ASSERT(&domain_proto_mtx, LCK_MTX_ASSERT_NOTOWNED); |
0a7de745 | 1115 | } |
39236c6e | 1116 | |
0a7de745 | 1117 | return (domain_unguard_t)(const void*)marks; |
39236c6e A |
1118 | } |
1119 | ||
1120 | void | |
1121 | domain_unguard_release(domain_unguard_t unguard) | |
1122 | { | |
1123 | net_thread_marks_t marks = (net_thread_marks_t)(const void*)unguard; | |
1124 | ||
1125 | if (marks != net_thread_marks_none) { | |
5ba3f43e | 1126 | LCK_MTX_ASSERT(&domain_proto_mtx, LCK_MTX_ASSERT_NOTOWNED); |
39236c6e A |
1127 | lck_mtx_lock(&domain_proto_mtx); |
1128 | net_thread_unmarks_pop(marks); | |
0a7de745 | 1129 | } else { |
5ba3f43e | 1130 | LCK_MTX_ASSERT(&domain_proto_mtx, LCK_MTX_ASSERT_OWNED); |
0a7de745 | 1131 | } |
1c79356b | 1132 | } |
3e170ce0 | 1133 | |
5ba3f43e | 1134 | |
3e170ce0 | 1135 | #if (DEVELOPMENT || DEBUG) |
0a7de745 | 1136 | |
3e170ce0 A |
1137 | static int |
1138 | sysctl_do_drain_domains SYSCTL_HANDLER_ARGS | |
1139 | { | |
1140 | #pragma unused(arg1, arg2) | |
1141 | int error; | |
1142 | int dummy = 0; | |
1143 | ||
0a7de745 A |
1144 | error = sysctl_handle_int(oidp, &dummy, 0, req); |
1145 | if (error || req->newptr == USER_ADDR_NULL) { | |
1146 | return error; | |
1147 | } | |
3e170ce0 A |
1148 | |
1149 | net_drain_domains(); | |
1150 | ||
0a7de745 | 1151 | return 0; |
3e170ce0 A |
1152 | } |
1153 | ||
1154 | #endif /* DEVELOPMENT || DEBUG */ |