]> git.saurik.com Git - apple/xnu.git/blame_incremental - bsd/net/if_ports_used.c
xnu-6153.41.3.tar.gz
[apple/xnu.git] / bsd / net / if_ports_used.c
... / ...
CommitLineData
1/*
2 * Copyright (c) 2017-2018 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
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.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
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
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
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.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29#include <sys/types.h>
30#include <sys/sysctl.h>
31#include <sys/time.h>
32#include <sys/mcache.h>
33#include <sys/malloc.h>
34#include <sys/kauth.h>
35#include <sys/bitstring.h>
36#include <sys/priv.h>
37#include <sys/protosw.h>
38#include <sys/socket.h>
39
40#include <kern/locks.h>
41#include <kern/zalloc.h>
42
43#include <libkern/libkern.h>
44
45#include <net/kpi_interface.h>
46#include <net/if_var.h>
47#include <net/if_ports_used.h>
48
49#include <netinet/in_pcb.h>
50#include <netinet/tcp_var.h>
51#include <netinet/tcp_fsm.h>
52
53
54#include <stdbool.h>
55
56#include <os/log.h>
57
58extern bool IOPMCopySleepWakeUUIDKey(char *buffer, size_t buf_len);
59
60SYSCTL_DECL(_net_link_generic_system);
61
62SYSCTL_NODE(_net_link_generic_system, OID_AUTO, port_used,
63 CTLFLAG_RW | CTLFLAG_LOCKED, 0, "if port used");
64
65static uuid_t current_wakeuuid;
66SYSCTL_OPAQUE(_net_link_generic_system_port_used, OID_AUTO, current_wakeuuid,
67 CTLFLAG_RD | CTLFLAG_LOCKED,
68 current_wakeuuid, sizeof(uuid_t), "S,uuid_t", "");
69
70static int sysctl_net_port_info_list SYSCTL_HANDLER_ARGS;
71SYSCTL_PROC(_net_link_generic_system_port_used, OID_AUTO, list,
72 CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_LOCKED, 0, 0,
73 sysctl_net_port_info_list, "S,xnpigen", "");
74
75static int use_test_wakeuuid = 0;
76static uuid_t test_wakeuuid;
77static uuid_string_t test_wakeuuid_str;
78
79#if (DEVELOPMENT || DEBUG)
80SYSCTL_INT(_net_link_generic_system_port_used, OID_AUTO, use_test_wakeuuid,
81 CTLFLAG_RW | CTLFLAG_LOCKED,
82 &use_test_wakeuuid, 0, "");
83
84int sysctl_new_test_wakeuuid SYSCTL_HANDLER_ARGS;
85SYSCTL_PROC(_net_link_generic_system_port_used, OID_AUTO, new_test_wakeuuid,
86 CTLTYPE_STRUCT | CTLFLAG_RW | CTLFLAG_LOCKED, 0, 0,
87 sysctl_new_test_wakeuuid, "S,uuid_t", "");
88
89int sysctl_clear_test_wakeuuid SYSCTL_HANDLER_ARGS;
90SYSCTL_PROC(_net_link_generic_system_port_used, OID_AUTO, clear_test_wakeuuid,
91 CTLTYPE_STRUCT | CTLFLAG_RW | CTLFLAG_LOCKED, 0, 0,
92 sysctl_clear_test_wakeuuid, "S,uuid_t", "");
93
94int sysctl_test_wakeuuid_str SYSCTL_HANDLER_ARGS;
95SYSCTL_PROC(_net_link_generic_system_port_used, OID_AUTO, test_wakeuuid_str,
96 CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_LOCKED, 0, 0,
97 sysctl_test_wakeuuid_str, "A", "");
98
99SYSCTL_OPAQUE(_net_link_generic_system_port_used, OID_AUTO, test_wakeuuid,
100 CTLFLAG_RD | CTLFLAG_LOCKED,
101 test_wakeuuid, sizeof(uuid_t), "S,uuid_t", "");
102#endif /* (DEVELOPMENT || DEBUG) */
103
104static int sysctl_get_ports_used SYSCTL_HANDLER_ARGS;
105SYSCTL_NODE(_net_link_generic_system, OID_AUTO, get_ports_used,
106 CTLFLAG_RD | CTLFLAG_LOCKED,
107 sysctl_get_ports_used, "");
108
109static uint32_t net_port_entry_count = 0;
110SYSCTL_UINT(_net_link_generic_system_port_used, OID_AUTO, entry_count,
111 CTLFLAG_RW | CTLFLAG_LOCKED,
112 &net_port_entry_count, 0, "");
113
114static uint32_t net_port_entry_gen = 0;
115SYSCTL_UINT(_net_link_generic_system_port_used, OID_AUTO, entry_gen,
116 CTLFLAG_RW | CTLFLAG_LOCKED,
117 &net_port_entry_gen, 0, "");
118
119static int if_ports_used_verbose = 0;
120SYSCTL_INT(_net_link_generic_system_port_used, OID_AUTO, verbose,
121 CTLFLAG_RW | CTLFLAG_LOCKED,
122 &if_ports_used_verbose, 0, "");
123
124static unsigned long wakeuuid_not_set_count = 0;
125SYSCTL_ULONG(_net_link_generic_system_port_used, OID_AUTO,
126 wakeuuid_not_set_count, CTLFLAG_RD | CTLFLAG_LOCKED,
127 &wakeuuid_not_set_count, 0);
128
129struct timeval wakeuuid_not_set_last_time;
130int sysctl_wakeuuid_not_set_last_time SYSCTL_HANDLER_ARGS;
131static SYSCTL_PROC(_net_link_generic_system_port_used, OID_AUTO,
132 wakeuuid_not_set_last_time, CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_LOCKED,
133 0, 0, sysctl_wakeuuid_not_set_last_time, "S,timeval", "");
134
135char wakeuuid_not_set_last_if[IFXNAMSIZ];
136int sysctl_wakeuuid_not_set_last_if SYSCTL_HANDLER_ARGS;
137static SYSCTL_PROC(_net_link_generic_system_port_used, OID_AUTO,
138 wakeuuid_not_set_last_if, CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_LOCKED,
139 0, 0, sysctl_wakeuuid_not_set_last_if, "A", "");
140
141
142static int if_ports_used_inited = 0;
143
144decl_lck_mtx_data(static, net_port_entry_head_lock);
145static lck_grp_t *net_port_entry_head_lock_group;
146
147struct net_port_entry {
148 SLIST_ENTRY(net_port_entry) npe_next;
149 struct net_port_info npe_npi;
150};
151
152static struct zone *net_port_entry_zone = NULL;
153
154#define NET_PORT_ENTRY_ZONE_MAX 128
155#define NET_PORT_ENTRY_ZONE_NAME "net_port_entry"
156
157static SLIST_HEAD(net_port_entry_list, net_port_entry) net_port_entry_list =
158 SLIST_HEAD_INITIALIZER(&net_port_entry_list);
159
160struct timeval wakeuiid_last_check;
161
162void
163if_ports_used_init(void)
164{
165 if (if_ports_used_inited == 0) {
166 lck_grp_attr_t *lck_grp_attributes = NULL;
167 lck_attr_t *lck_attributes = NULL;
168
169 timerclear(&wakeuiid_last_check);
170 uuid_clear(current_wakeuuid);
171 uuid_clear(test_wakeuuid);
172
173 lck_grp_attributes = lck_grp_attr_alloc_init();
174 net_port_entry_head_lock_group = lck_grp_alloc_init(
175 "net port entry lock", lck_grp_attributes);
176
177 lck_attributes = lck_attr_alloc_init();
178 if (lck_attributes == NULL) {
179 panic("%s: lck_attr_alloc_init() failed", __func__);
180 }
181 lck_mtx_init(&net_port_entry_head_lock,
182 net_port_entry_head_lock_group,
183 lck_attributes);
184
185 net_port_entry_count = 0;
186 net_port_entry_zone = zinit(sizeof(struct net_port_entry),
187 NET_PORT_ENTRY_ZONE_MAX * sizeof(struct net_port_entry),
188 0, NET_PORT_ENTRY_ZONE_NAME);
189 if (net_port_entry_zone == NULL) {
190 panic("%s: zinit(%s) failed", __func__,
191 NET_PORT_ENTRY_ZONE_NAME);
192 }
193 zone_change(net_port_entry_zone, Z_EXPAND, TRUE);
194 zone_change(net_port_entry_zone, Z_CALLERACCT, FALSE);
195
196 if_ports_used_inited = 1;
197
198 lck_attr_free(lck_attributes);
199 lck_grp_attr_free(lck_grp_attributes);
200 }
201}
202
203static void
204net_port_entry_list_clear(void)
205{
206 struct net_port_entry *npe;
207
208 LCK_MTX_ASSERT(&net_port_entry_head_lock, LCK_MTX_ASSERT_OWNED);
209
210 while ((npe = SLIST_FIRST(&net_port_entry_list)) != NULL) {
211 SLIST_REMOVE_HEAD(&net_port_entry_list, npe_next);
212
213 zfree(net_port_entry_zone, npe);
214 }
215 net_port_entry_count = 0;
216 net_port_entry_gen++;
217}
218
219static bool
220get_test_wake_uuid(uuid_string_t wakeuuid_str, size_t len)
221{
222 if (__improbable(use_test_wakeuuid)) {
223 if (!uuid_is_null(test_wakeuuid)) {
224 if (wakeuuid_str != NULL && len != 0) {
225 uuid_unparse(test_wakeuuid, wakeuuid_str);
226 }
227 return true;
228 } else if (strlen(test_wakeuuid_str) != 0) {
229 if (wakeuuid_str != NULL && len != 0) {
230 strlcpy(wakeuuid_str, test_wakeuuid_str, len);
231 }
232 return true;
233 } else {
234 return false;
235 }
236 } else {
237 return false;
238 }
239}
240
241static bool
242is_wakeuuid_set(void)
243{
244 /*
245 * IOPMCopySleepWakeUUIDKey() tells if SleepWakeUUID is currently set
246 * That means we are currently in a sleep/wake cycle
247 */
248 return get_test_wake_uuid(NULL, 0) || IOPMCopySleepWakeUUIDKey(NULL, 0);
249}
250
251void
252if_ports_used_update_wakeuuid(struct ifnet *ifp)
253{
254 uuid_t wakeuuid;
255 bool wakeuuid_is_set = false;
256 bool updated = false;
257 uuid_string_t wakeuuid_str;
258
259 uuid_clear(wakeuuid);
260
261 if (__improbable(use_test_wakeuuid)) {
262 wakeuuid_is_set = get_test_wake_uuid(wakeuuid_str,
263 sizeof(wakeuuid_str));
264 } else {
265 wakeuuid_is_set = IOPMCopySleepWakeUUIDKey(wakeuuid_str,
266 sizeof(wakeuuid_str));
267 }
268
269 if (wakeuuid_is_set) {
270 if (uuid_parse(wakeuuid_str, wakeuuid) != 0) {
271 os_log(OS_LOG_DEFAULT,
272 "%s: IOPMCopySleepWakeUUIDKey got bad value %s\n",
273 __func__, wakeuuid_str);
274 wakeuuid_is_set = false;
275 }
276 }
277
278 if (!wakeuuid_is_set) {
279 if (if_ports_used_verbose > 0) {
280 os_log_info(OS_LOG_DEFAULT,
281 "%s: SleepWakeUUID not set, "
282 "don't update the port list for %s\n",
283 __func__, ifp != NULL ? if_name(ifp) : "");
284 }
285 wakeuuid_not_set_count += 1;
286 if (ifp != NULL) {
287 microtime(&wakeuuid_not_set_last_time);
288 strlcpy(wakeuuid_not_set_last_if, if_name(ifp),
289 sizeof(wakeuuid_not_set_last_if));
290 }
291 return;
292 }
293
294 lck_mtx_lock(&net_port_entry_head_lock);
295 if (uuid_compare(wakeuuid, current_wakeuuid) != 0) {
296 net_port_entry_list_clear();
297 uuid_copy(current_wakeuuid, wakeuuid);
298 updated = true;
299 }
300 /*
301 * Record the time last checked
302 */
303 microuptime(&wakeuiid_last_check);
304 lck_mtx_unlock(&net_port_entry_head_lock);
305
306 if (updated && if_ports_used_verbose > 0) {
307 uuid_string_t uuid_str;
308
309 uuid_unparse(current_wakeuuid, uuid_str);
310 log(LOG_ERR, "%s: current wakeuuid %s\n",
311 __func__,
312 uuid_str);
313 }
314}
315
316static bool
317net_port_info_equal(const struct net_port_info *x,
318 const struct net_port_info *y)
319{
320 ASSERT(x != NULL && y != NULL);
321
322 if (x->npi_if_index == y->npi_if_index &&
323 x->npi_local_port == y->npi_local_port &&
324 x->npi_foreign_port == y->npi_foreign_port &&
325 x->npi_owner_pid == y->npi_owner_pid &&
326 x->npi_effective_pid == y->npi_effective_pid &&
327 x->npi_flags == y->npi_flags &&
328 memcmp(&x->npi_local_addr_, &y->npi_local_addr_,
329 sizeof(union in_addr_4_6)) == 0 &&
330 memcmp(&x->npi_foreign_addr_, &y->npi_foreign_addr_,
331 sizeof(union in_addr_4_6)) == 0) {
332 return true;
333 }
334 return false;
335}
336
337static bool
338net_port_info_has_entry(const struct net_port_info *npi)
339{
340 struct net_port_entry *npe;
341
342 LCK_MTX_ASSERT(&net_port_entry_head_lock, LCK_MTX_ASSERT_OWNED);
343
344 SLIST_FOREACH(npe, &net_port_entry_list, npe_next) {
345 if (net_port_info_equal(&npe->npe_npi, npi)) {
346 return true;
347 }
348 }
349
350 return false;
351}
352
353static bool
354net_port_info_add_entry(const struct net_port_info *npi)
355{
356 struct net_port_entry *npe = NULL;
357 uint32_t num = 0;
358 bool entry_added = false;
359
360 ASSERT(npi != NULL);
361
362 if (__improbable(is_wakeuuid_set() == false)) {
363 if (if_ports_used_verbose > 0) {
364 log(LOG_ERR, "%s: wakeuuid not set %u not adding "
365 "port: %u flags: 0x%xif: %u pid: %u epid %u\n",
366 __func__,
367 ntohs(npi->npi_local_port),
368 npi->npi_flags,
369 npi->npi_if_index,
370 npi->npi_owner_pid,
371 npi->npi_effective_pid);
372 }
373 return 0;
374 }
375
376 npe = zalloc(net_port_entry_zone);
377 if (__improbable(npe == NULL)) {
378 log(LOG_ERR, "%s: zalloc() failed for "
379 "port: %u flags: 0x%x if: %u pid: %u epid %u\n",
380 __func__,
381 ntohs(npi->npi_local_port),
382 npi->npi_flags,
383 npi->npi_if_index,
384 npi->npi_owner_pid,
385 npi->npi_effective_pid);
386 return 0;
387 }
388 bzero(npe, sizeof(struct net_port_entry));
389
390 memcpy(&npe->npe_npi, npi, sizeof(npe->npe_npi));
391
392 lck_mtx_lock(&net_port_entry_head_lock);
393
394 if (net_port_info_has_entry(npi) == false) {
395 SLIST_INSERT_HEAD(&net_port_entry_list, npe, npe_next);
396 num = net_port_entry_count++;
397 entry_added = true;
398
399 if (if_ports_used_verbose > 0) {
400 log(LOG_ERR, "%s: num %u for "
401 "port: %u flags: 0x%x if: %u pid: %u epid %u\n",
402 __func__,
403 num,
404 ntohs(npi->npi_local_port),
405 npi->npi_flags,
406 npi->npi_if_index,
407 npi->npi_owner_pid,
408 npi->npi_effective_pid);
409 }
410 } else {
411 if (if_ports_used_verbose > 0) {
412 log(LOG_ERR, "%s: entry already added "
413 "port: %u flags: 0x%x if: %u pid: %u epid %u\n",
414 __func__,
415 ntohs(npi->npi_local_port),
416 npi->npi_flags,
417 npi->npi_if_index,
418 npi->npi_owner_pid,
419 npi->npi_effective_pid);
420 }
421 }
422
423 lck_mtx_unlock(&net_port_entry_head_lock);
424
425 if (entry_added == false) {
426 zfree(net_port_entry_zone, npe);
427 npe = NULL;
428 }
429 return entry_added;
430}
431
432#if (DEVELOPMENT || DEBUG)
433int
434sysctl_new_test_wakeuuid SYSCTL_HANDLER_ARGS
435{
436#pragma unused(oidp, arg1, arg2)
437 int error = 0;
438
439 if (kauth_cred_issuser(kauth_cred_get()) == 0) {
440 return EPERM;
441 }
442 if (req->oldptr == USER_ADDR_NULL) {
443 req->oldidx = sizeof(uuid_t);
444 return 0;
445 }
446 if (req->newptr != USER_ADDR_NULL) {
447 uuid_generate(test_wakeuuid);
448 }
449 error = SYSCTL_OUT(req, test_wakeuuid,
450 MIN(sizeof(uuid_t), req->oldlen));
451
452 return error;
453}
454
455int
456sysctl_clear_test_wakeuuid SYSCTL_HANDLER_ARGS
457{
458#pragma unused(oidp, arg1, arg2)
459 int error = 0;
460
461 if (kauth_cred_issuser(kauth_cred_get()) == 0) {
462 return EPERM;
463 }
464 if (req->oldptr == USER_ADDR_NULL) {
465 req->oldidx = sizeof(uuid_t);
466 return 0;
467 }
468 if (req->newptr != USER_ADDR_NULL) {
469 uuid_clear(test_wakeuuid);
470 }
471 error = SYSCTL_OUT(req, test_wakeuuid,
472 MIN(sizeof(uuid_t), req->oldlen));
473
474 return error;
475}
476
477int
478sysctl_test_wakeuuid_str SYSCTL_HANDLER_ARGS
479{
480#pragma unused(oidp, arg1, arg2)
481 int error = 0;
482 int changed;
483
484 if (kauth_cred_issuser(kauth_cred_get()) == 0) {
485 return EPERM;
486 }
487 error = sysctl_io_string(req, test_wakeuuid_str, sizeof(test_wakeuuid_str), 1, &changed);
488 if (changed) {
489 os_log_info(OS_LOG_DEFAULT, "%s: test_wakeuuid_str %s",
490 __func__, test_wakeuuid_str);
491 }
492
493 return error;
494}
495
496#endif /* (DEVELOPMENT || DEBUG) */
497
498int
499sysctl_wakeuuid_not_set_last_time SYSCTL_HANDLER_ARGS
500{
501#pragma unused(oidp, arg1, arg2)
502
503 if (proc_is64bit(req->p)) {
504 struct user64_timeval tv = {};
505
506 tv.tv_sec = wakeuuid_not_set_last_time.tv_sec;
507 tv.tv_usec = wakeuuid_not_set_last_time.tv_usec;
508 return SYSCTL_OUT(req, &tv, sizeof(tv));
509 } else {
510 struct user32_timeval tv = {};
511
512 tv.tv_sec = wakeuuid_not_set_last_time.tv_sec;
513 tv.tv_usec = wakeuuid_not_set_last_time.tv_usec;
514 return SYSCTL_OUT(req, &tv, sizeof(tv));
515 }
516}
517
518int
519sysctl_wakeuuid_not_set_last_if SYSCTL_HANDLER_ARGS
520{
521#pragma unused(oidp, arg1, arg2)
522
523 return SYSCTL_OUT(req, &wakeuuid_not_set_last_if,
524 strlen(wakeuuid_not_set_last_if) + 1);
525}
526
527static int
528sysctl_net_port_info_list SYSCTL_HANDLER_ARGS
529{
530#pragma unused(oidp, arg1, arg2)
531 int error = 0;
532 struct xnpigen xnpigen;
533 struct net_port_entry *npe;
534
535 if ((error = priv_check_cred(kauth_cred_get(),
536 PRIV_NET_PRIVILEGED_NETWORK_STATISTICS, 0)) != 0) {
537 return EPERM;
538 }
539 lck_mtx_lock(&net_port_entry_head_lock);
540
541 if (req->oldptr == USER_ADDR_NULL) {
542 /* Add a 25 % cushion */
543 uint32_t cnt = net_port_entry_count;
544 cnt += cnt >> 4;
545 req->oldidx = sizeof(struct xnpigen) +
546 cnt * sizeof(struct net_port_info);
547 goto done;
548 }
549
550 memset(&xnpigen, 0, sizeof(struct xnpigen));
551 xnpigen.xng_len = sizeof(struct xnpigen);
552 xnpigen.xng_gen = net_port_entry_gen;
553 uuid_copy(xnpigen.xng_wakeuuid, current_wakeuuid);
554 xnpigen.xng_npi_count = net_port_entry_count;
555 xnpigen.xng_npi_size = sizeof(struct net_port_info);
556 error = SYSCTL_OUT(req, &xnpigen, sizeof(xnpigen));
557 if (error != 0) {
558 printf("%s: SYSCTL_OUT(xnpigen) error %d\n",
559 __func__, error);
560 goto done;
561 }
562
563 SLIST_FOREACH(npe, &net_port_entry_list, npe_next) {
564 error = SYSCTL_OUT(req, &npe->npe_npi,
565 sizeof(struct net_port_info));
566 if (error != 0) {
567 printf("%s: SYSCTL_OUT(npi) error %d\n",
568 __func__, error);
569 goto done;
570 }
571 }
572done:
573 lck_mtx_unlock(&net_port_entry_head_lock);
574
575 return error;
576}
577
578/*
579 * Mirror the arguments of ifnet_get_local_ports_extended()
580 * ifindex
581 * protocol
582 * flags
583 */
584static int
585sysctl_get_ports_used SYSCTL_HANDLER_ARGS
586{
587#pragma unused(oidp)
588 int *name = (int *)arg1;
589 int namelen = arg2;
590 int error = 0;
591 int idx;
592 protocol_family_t protocol;
593 u_int32_t flags;
594 ifnet_t ifp = NULL;
595 u_int8_t *bitfield = NULL;
596
597 if (req->newptr != USER_ADDR_NULL) {
598 error = EPERM;
599 goto done;
600 }
601 /*
602 * 3 is the required number of parameters: ifindex, protocol and flags
603 */
604 if (namelen != 3) {
605 error = ENOENT;
606 goto done;
607 }
608
609 if (req->oldptr == USER_ADDR_NULL) {
610 req->oldidx = bitstr_size(IP_PORTRANGE_SIZE);
611 goto done;
612 }
613 if (req->oldlen < bitstr_size(IP_PORTRANGE_SIZE)) {
614 error = ENOMEM;
615 goto done;
616 }
617
618 idx = name[0];
619 protocol = name[1];
620 flags = name[2];
621
622 ifnet_head_lock_shared();
623 if (!IF_INDEX_IN_RANGE(idx)) {
624 ifnet_head_done();
625 error = ENOENT;
626 goto done;
627 }
628 ifp = ifindex2ifnet[idx];
629 ifnet_head_done();
630
631 bitfield = _MALLOC(bitstr_size(IP_PORTRANGE_SIZE), M_TEMP,
632 M_WAITOK | M_ZERO);
633 if (bitfield == NULL) {
634 error = ENOMEM;
635 goto done;
636 }
637 error = ifnet_get_local_ports_extended(ifp, protocol, flags, bitfield);
638 if (error != 0) {
639 printf("%s: ifnet_get_local_ports_extended() error %d\n",
640 __func__, error);
641 goto done;
642 }
643 error = SYSCTL_OUT(req, bitfield, bitstr_size(IP_PORTRANGE_SIZE));
644done:
645 if (bitfield != NULL) {
646 _FREE(bitfield, M_TEMP);
647 }
648 return error;
649}
650
651__private_extern__ void
652if_ports_used_add_inpcb(const uint32_t ifindex, const struct inpcb *inp)
653{
654 struct net_port_info npi;
655 struct socket *so = inp->inp_socket;
656
657 bzero(&npi, sizeof(struct net_port_info));
658
659 npi.npi_if_index = ifindex;
660
661 npi.npi_flags |= NPIF_SOCKET;
662
663 npi.npi_timestamp.tv_sec = wakeuiid_last_check.tv_sec;
664 npi.npi_timestamp.tv_usec = wakeuiid_last_check.tv_usec;
665
666 if (SOCK_PROTO(so) == IPPROTO_TCP) {
667 struct tcpcb *tp = intotcpcb(inp);
668
669 npi.npi_flags |= NPIF_TCP;
670 if (tp != NULL && tp->t_state == TCPS_LISTEN) {
671 npi.npi_flags |= NPIF_LISTEN;
672 }
673 } else if (SOCK_PROTO(so) == IPPROTO_UDP) {
674 npi.npi_flags |= NPIF_UDP;
675 } else {
676 panic("%s: unexpected protocol %u for inp %p\n", __func__,
677 SOCK_PROTO(inp->inp_socket), inp);
678 }
679
680 uuid_copy(npi.npi_flow_uuid, inp->necp_client_uuid);
681
682 npi.npi_local_port = inp->inp_lport;
683 npi.npi_foreign_port = inp->inp_fport;
684
685 /*
686 * Take in account IPv4 addresses mapped on IPv6
687 */
688 if ((inp->inp_vflag & INP_IPV6) != 0 && (inp->inp_flags & IN6P_IPV6_V6ONLY) == 0 &&
689 (inp->inp_vflag & (INP_IPV6 | INP_IPV4)) == (INP_IPV6 | INP_IPV4)) {
690 npi.npi_flags |= NPIF_IPV6 | NPIF_IPV4;
691 memcpy(&npi.npi_local_addr_in6,
692 &inp->in6p_laddr, sizeof(struct in6_addr));
693 } else if (inp->inp_vflag & INP_IPV4) {
694 npi.npi_flags |= NPIF_IPV4;
695 npi.npi_local_addr_in = inp->inp_laddr;
696 npi.npi_foreign_addr_in = inp->inp_faddr;
697 } else {
698 npi.npi_flags |= NPIF_IPV6;
699 memcpy(&npi.npi_local_addr_in6,
700 &inp->in6p_laddr, sizeof(struct in6_addr));
701 memcpy(&npi.npi_foreign_addr_in6,
702 &inp->in6p_faddr, sizeof(struct in6_addr));
703 }
704
705 npi.npi_owner_pid = so->last_pid;
706
707 if (so->last_pid != 0) {
708 proc_name(so->last_pid, npi.npi_owner_pname,
709 sizeof(npi.npi_owner_pname));
710 }
711
712 if (so->so_flags & SOF_DELEGATED) {
713 npi.npi_flags |= NPIF_DELEGATED;
714 npi.npi_effective_pid = so->e_pid;
715 if (so->e_pid != 0) {
716 proc_name(so->e_pid, npi.npi_effective_pname,
717 sizeof(npi.npi_effective_pname));
718 }
719 } else {
720 npi.npi_effective_pid = so->last_pid;
721 if (so->last_pid != 0) {
722 strlcpy(npi.npi_effective_pname, npi.npi_owner_pname,
723 sizeof(npi.npi_effective_pname));
724 }
725 }
726
727 (void) net_port_info_add_entry(&npi);
728}
729