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