2 * Copyright (c) 2010-2013 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
29 #include <sys/param.h>
30 #include <sys/types.h>
31 #include <sys/kpi_mbuf.h>
32 #include <sys/socket.h>
33 #include <sys/kern_control.h>
34 #include <sys/mcache.h>
35 #include <sys/socketvar.h>
36 #include <sys/sysctl.h>
37 #include <sys/queue.h>
40 #include <kern/clock.h>
41 #include <kern/debug.h>
43 #include <libkern/libkern.h>
44 #include <libkern/OSMalloc.h>
45 #include <libkern/OSAtomic.h>
46 #include <libkern/locks.h>
49 #include <net/if_var.h>
50 #include <net/if_types.h>
51 #include <net/route.h>
52 #include <net/ntstat.h>
54 #include <netinet/ip_var.h>
55 #include <netinet/in_pcb.h>
56 #include <netinet/in_var.h>
57 #include <netinet/tcp.h>
58 #include <netinet/tcp_var.h>
59 #include <netinet/tcp_fsm.h>
60 #include <netinet/udp.h>
61 #include <netinet/udp_var.h>
62 #include <netinet6/in6_pcb.h>
63 #include <netinet6/in6_var.h>
65 __private_extern__
int nstat_collect
= 1;
66 SYSCTL_INT(_net
, OID_AUTO
, statistics
, CTLFLAG_RW
| CTLFLAG_LOCKED
,
67 &nstat_collect
, 0, "Collect detailed statistics");
69 static int nstat_privcheck
= 0;
70 SYSCTL_INT(_net
, OID_AUTO
, statistics_privcheck
, CTLFLAG_RW
| CTLFLAG_LOCKED
,
71 &nstat_privcheck
, 0, "Entitlement check");
75 NSTAT_FLAG_CLEANUP
= (1 << 0),
76 NSTAT_FLAG_REQCOUNTS
= (1 << 1),
77 NSTAT_FLAG_REQDESCS
= (1 << 2)
80 typedef struct nstat_control_state
82 struct nstat_control_state
*ncs_next
;
83 u_int32_t ncs_watching
;
84 decl_lck_mtx_data(, mtx
);
85 kern_ctl_ref ncs_kctl
;
87 nstat_src_ref_t ncs_next_srcref
;
88 struct nstat_src
*ncs_srcs
;
90 } nstat_control_state
;
92 typedef struct nstat_provider
94 struct nstat_provider
*next
;
95 nstat_provider_id_t nstat_provider_id
;
96 size_t nstat_descriptor_length
;
97 errno_t (*nstat_lookup
)(const void *data
, u_int32_t length
, nstat_provider_cookie_t
*out_cookie
);
98 int (*nstat_gone
)(nstat_provider_cookie_t cookie
);
99 errno_t (*nstat_counts
)(nstat_provider_cookie_t cookie
, struct nstat_counts
*out_counts
, int *out_gone
);
100 errno_t (*nstat_watcher_add
)(nstat_control_state
*state
);
101 void (*nstat_watcher_remove
)(nstat_control_state
*state
);
102 errno_t (*nstat_copy_descriptor
)(nstat_provider_cookie_t cookie
, void *data
, u_int32_t len
);
103 void (*nstat_release
)(nstat_provider_cookie_t cookie
, boolean_t locked
);
107 typedef struct nstat_src
109 struct nstat_src
*next
;
110 nstat_src_ref_t srcref
;
111 nstat_provider
*provider
;
112 nstat_provider_cookie_t cookie
;
116 static errno_t
nstat_control_send_counts(nstat_control_state
*,
117 nstat_src
*, unsigned long long, int *);
118 static int nstat_control_send_description(nstat_control_state
*state
, nstat_src
*src
, u_int64_t context
);
119 static errno_t
nstat_control_send_removed(nstat_control_state
*, nstat_src
*);
120 static void nstat_control_cleanup_source(nstat_control_state
*state
, nstat_src
*src
,
123 static u_int32_t nstat_udp_watchers
= 0;
124 static u_int32_t nstat_tcp_watchers
= 0;
126 static void nstat_control_register(void);
128 static volatile OSMallocTag nstat_malloc_tag
= NULL
;
129 static nstat_control_state
*nstat_controls
= NULL
;
130 static uint64_t nstat_idle_time
= 0;
131 static decl_lck_mtx_data(, nstat_mtx
);
135 const struct sockaddr
*src
,
136 struct sockaddr
*dst
,
139 if (src
->sa_len
> maxlen
) return;
141 bcopy(src
, dst
, src
->sa_len
);
142 if (src
->sa_family
== AF_INET6
&&
143 src
->sa_len
>= sizeof(struct sockaddr_in6
))
145 struct sockaddr_in6
*sin6
= (struct sockaddr_in6
*)(void *)dst
;
146 if (IN6_IS_SCOPE_EMBED(&sin6
->sin6_addr
))
148 if (sin6
->sin6_scope_id
== 0)
149 sin6
->sin6_scope_id
= ntohs(sin6
->sin6_addr
.__u6_addr
.__u6_addr16
[1]);
150 sin6
->sin6_addr
.__u6_addr
.__u6_addr16
[1] = 0;
156 nstat_ip_to_sockaddr(
157 const struct in_addr
*ip
,
159 struct sockaddr_in
*sin
,
162 if (maxlen
< sizeof(struct sockaddr_in
))
165 sin
->sin_family
= AF_INET
;
166 sin
->sin_len
= sizeof(*sin
);
167 sin
->sin_port
= port
;
172 nstat_ip6_to_sockaddr(
173 const struct in6_addr
*ip6
,
175 struct sockaddr_in6
*sin6
,
178 if (maxlen
< sizeof(struct sockaddr_in6
))
181 sin6
->sin6_family
= AF_INET6
;
182 sin6
->sin6_len
= sizeof(*sin6
);
183 sin6
->sin6_port
= port
;
184 sin6
->sin6_addr
= *ip6
;
185 if (IN6_IS_SCOPE_EMBED(&sin6
->sin6_addr
))
187 sin6
->sin6_scope_id
= ntohs(sin6
->sin6_addr
.__u6_addr
.__u6_addr16
[1]);
188 sin6
->sin6_addr
.__u6_addr
.__u6_addr16
[1] = 0;
192 #pragma mark -- Network Statistic Providers --
194 static errno_t
nstat_control_source_add(u_int64_t context
, nstat_control_state
*state
, nstat_provider
*provider
, nstat_provider_cookie_t cookie
);
195 struct nstat_provider
*nstat_providers
= NULL
;
197 static struct nstat_provider
*
198 nstat_find_provider_by_id(
199 nstat_provider_id_t id
)
201 struct nstat_provider
*provider
;
203 for (provider
= nstat_providers
; provider
!= NULL
; provider
= provider
->next
)
205 if (provider
->nstat_provider_id
== id
)
214 nstat_provider_id_t id
,
217 nstat_provider
**out_provider
,
218 nstat_provider_cookie_t
*out_cookie
)
220 *out_provider
= nstat_find_provider_by_id(id
);
221 if (*out_provider
== NULL
)
226 return (*out_provider
)->nstat_lookup(data
, length
, out_cookie
);
229 static void nstat_init_route_provider(void);
230 static void nstat_init_tcp_provider(void);
231 static void nstat_init_udp_provider(void);
232 static void nstat_init_ifnet_provider(void);
234 __private_extern__
void
237 if (nstat_malloc_tag
!= NULL
) return;
239 OSMallocTag tag
= OSMalloc_Tagalloc(NET_STAT_CONTROL_NAME
, OSMT_DEFAULT
);
240 if (!OSCompareAndSwapPtr(NULL
, tag
, &nstat_malloc_tag
))
242 OSMalloc_Tagfree(tag
);
243 tag
= nstat_malloc_tag
;
247 // we need to initialize other things, we do it here as this code path will only be hit once;
248 nstat_init_route_provider();
249 nstat_init_tcp_provider();
250 nstat_init_udp_provider();
251 nstat_init_ifnet_provider();
252 nstat_control_register();
256 #pragma mark -- Aligned Buffer Allocation --
265 nstat_malloc_aligned(
270 struct align_header
*hdr
= NULL
;
271 u_int32_t size
= length
+ sizeof(*hdr
) + alignment
- 1;
273 u_int8_t
*buffer
= OSMalloc(size
, tag
);
274 if (buffer
== NULL
) return NULL
;
276 u_int8_t
*aligned
= buffer
+ sizeof(*hdr
);
277 aligned
= (u_int8_t
*)P2ROUNDUP(aligned
, alignment
);
279 hdr
= (struct align_header
*)(void *)(aligned
- sizeof(*hdr
));
280 hdr
->offset
= aligned
- buffer
;
291 struct align_header
*hdr
= (struct align_header
*)(void *)((u_int8_t
*)buffer
- sizeof(*hdr
));
292 OSFree(((char*)buffer
) - hdr
->offset
, hdr
->length
, tag
);
295 #pragma mark -- Route Provider --
297 static nstat_provider nstat_route_provider
;
303 nstat_provider_cookie_t
*out_cookie
)
305 // rt_lookup doesn't take const params but it doesn't modify the parameters for
306 // the lookup. So...we use a union to eliminate the warning.
310 const struct sockaddr
*const_sa
;
313 const nstat_route_add_param
*param
= (const nstat_route_add_param
*)data
;
316 if (length
< sizeof(*param
))
321 if (param
->dst
.v4
.sin_family
== 0 ||
322 param
->dst
.v4
.sin_family
> AF_MAX
||
323 (param
->mask
.v4
.sin_family
!= 0 && param
->mask
.v4
.sin_family
!= param
->dst
.v4
.sin_family
))
328 if (param
->dst
.v4
.sin_len
> sizeof(param
->dst
) ||
329 (param
->mask
.v4
.sin_family
&& param
->mask
.v4
.sin_len
> sizeof(param
->mask
.v4
.sin_len
)))
334 // TBD: Need to validate length of sockaddr for different families?
335 dst
.const_sa
= (const struct sockaddr
*)¶m
->dst
;
336 mask
.const_sa
= param
->mask
.v4
.sin_family
? (const struct sockaddr
*)¶m
->mask
: NULL
;
338 struct radix_node_head
*rnh
= rt_tables
[dst
.sa
->sa_family
];
339 if (rnh
== NULL
) return EAFNOSUPPORT
;
341 lck_mtx_lock(rnh_lock
);
342 struct rtentry
*rt
= rt_lookup(TRUE
, dst
.sa
, mask
.sa
, rnh
, param
->ifindex
);
343 lck_mtx_unlock(rnh_lock
);
345 if (rt
) *out_cookie
= (nstat_provider_cookie_t
)rt
;
347 return rt
? 0 : ENOENT
;
352 nstat_provider_cookie_t cookie
)
354 struct rtentry
*rt
= (struct rtentry
*)cookie
;
355 return ((rt
->rt_flags
& RTF_UP
) == 0) ? 1 : 0;
360 nstat_provider_cookie_t cookie
,
361 struct nstat_counts
*out_counts
,
364 struct rtentry
*rt
= (struct rtentry
*)cookie
;
365 struct nstat_counts
*rt_stats
= rt
->rt_stats
;
369 if ((rt
->rt_flags
& RTF_UP
) == 0) *out_gone
= 1;
373 atomic_get_64(out_counts
->nstat_rxpackets
, &rt_stats
->nstat_rxpackets
);
374 atomic_get_64(out_counts
->nstat_rxbytes
, &rt_stats
->nstat_rxbytes
);
375 atomic_get_64(out_counts
->nstat_txpackets
, &rt_stats
->nstat_txpackets
);
376 atomic_get_64(out_counts
->nstat_txbytes
, &rt_stats
->nstat_txbytes
);
377 out_counts
->nstat_rxduplicatebytes
= rt_stats
->nstat_rxduplicatebytes
;
378 out_counts
->nstat_rxoutoforderbytes
= rt_stats
->nstat_rxoutoforderbytes
;
379 out_counts
->nstat_txretransmit
= rt_stats
->nstat_txretransmit
;
380 out_counts
->nstat_connectattempts
= rt_stats
->nstat_connectattempts
;
381 out_counts
->nstat_connectsuccesses
= rt_stats
->nstat_connectsuccesses
;
382 out_counts
->nstat_min_rtt
= rt_stats
->nstat_min_rtt
;
383 out_counts
->nstat_avg_rtt
= rt_stats
->nstat_avg_rtt
;
384 out_counts
->nstat_var_rtt
= rt_stats
->nstat_var_rtt
;
385 out_counts
->nstat_cell_rxbytes
= out_counts
->nstat_cell_txbytes
= 0;
388 bzero(out_counts
, sizeof(*out_counts
));
395 nstat_provider_cookie_t cookie
,
398 rtfree((struct rtentry
*)cookie
);
401 static u_int32_t nstat_route_watchers
= 0;
404 nstat_route_walktree_add(
405 struct radix_node
*rn
,
409 struct rtentry
*rt
= (struct rtentry
*)rn
;
410 nstat_control_state
*state
= (nstat_control_state
*)context
;
412 lck_mtx_assert(rnh_lock
, LCK_MTX_ASSERT_OWNED
);
414 /* RTF_UP can't change while rnh_lock is held */
415 if ((rt
->rt_flags
& RTF_UP
) != 0)
417 /* Clear RTPRF_OURS if the route is still usable */
419 if (rt_validate(rt
)) {
420 RT_ADDREF_LOCKED(rt
);
427 /* Otherwise if RTF_CONDEMNED, treat it as if it were down */
431 result
= nstat_control_source_add(0, state
, &nstat_route_provider
, rt
);
440 nstat_route_add_watcher(
441 nstat_control_state
*state
)
445 OSIncrementAtomic(&nstat_route_watchers
);
447 lck_mtx_lock(rnh_lock
);
448 for (i
= 1; i
< AF_MAX
; i
++)
450 struct radix_node_head
*rnh
;
454 result
= rnh
->rnh_walktree(rnh
, nstat_route_walktree_add
, state
);
460 lck_mtx_unlock(rnh_lock
);
465 __private_extern__
void
466 nstat_route_new_entry(
469 if (nstat_route_watchers
== 0)
472 lck_mtx_lock(&nstat_mtx
);
473 if ((rt
->rt_flags
& RTF_UP
) != 0)
475 nstat_control_state
*state
;
476 for (state
= nstat_controls
; state
; state
= state
->ncs_next
)
478 if ((state
->ncs_watching
& (1 << NSTAT_PROVIDER_ROUTE
)) != 0)
480 // this client is watching routes
481 // acquire a reference for the route
484 // add the source, if that fails, release the reference
485 if (nstat_control_source_add(0, state
, &nstat_route_provider
, rt
) != 0)
490 lck_mtx_unlock(&nstat_mtx
);
494 nstat_route_remove_watcher(
495 __unused nstat_control_state
*state
)
497 OSDecrementAtomic(&nstat_route_watchers
);
501 nstat_route_copy_descriptor(
502 nstat_provider_cookie_t cookie
,
506 nstat_route_descriptor
*desc
= (nstat_route_descriptor
*)data
;
507 if (len
< sizeof(*desc
))
511 bzero(desc
, sizeof(*desc
));
513 struct rtentry
*rt
= (struct rtentry
*)cookie
;
514 desc
->id
= (uintptr_t)rt
;
515 desc
->parent_id
= (uintptr_t)rt
->rt_parent
;
516 desc
->gateway_id
= (uintptr_t)rt
->rt_gwroute
;
521 if ((sa
= rt_key(rt
)))
522 nstat_copy_sa_out(sa
, &desc
->dst
.sa
, sizeof(desc
->dst
));
525 if ((sa
= rt_mask(rt
)) && sa
->sa_len
<= sizeof(desc
->mask
))
526 memcpy(&desc
->mask
, sa
, sa
->sa_len
);
529 if ((sa
= rt
->rt_gateway
))
530 nstat_copy_sa_out(sa
, &desc
->gateway
.sa
, sizeof(desc
->gateway
));
533 desc
->ifindex
= rt
->rt_ifp
->if_index
;
535 desc
->flags
= rt
->rt_flags
;
541 nstat_init_route_provider(void)
543 bzero(&nstat_route_provider
, sizeof(nstat_route_provider
));
544 nstat_route_provider
.nstat_descriptor_length
= sizeof(nstat_route_descriptor
);
545 nstat_route_provider
.nstat_provider_id
= NSTAT_PROVIDER_ROUTE
;
546 nstat_route_provider
.nstat_lookup
= nstat_route_lookup
;
547 nstat_route_provider
.nstat_gone
= nstat_route_gone
;
548 nstat_route_provider
.nstat_counts
= nstat_route_counts
;
549 nstat_route_provider
.nstat_release
= nstat_route_release
;
550 nstat_route_provider
.nstat_watcher_add
= nstat_route_add_watcher
;
551 nstat_route_provider
.nstat_watcher_remove
= nstat_route_remove_watcher
;
552 nstat_route_provider
.nstat_copy_descriptor
= nstat_route_copy_descriptor
;
553 nstat_route_provider
.next
= nstat_providers
;
554 nstat_providers
= &nstat_route_provider
;
557 #pragma mark -- Route Collection --
559 static struct nstat_counts
*
563 struct nstat_counts
*result
= rte
->rt_stats
;
564 if (result
) return result
;
566 if (nstat_malloc_tag
== NULL
) nstat_init();
568 result
= nstat_malloc_aligned(sizeof(*result
), sizeof(u_int64_t
), nstat_malloc_tag
);
569 if (!result
) return result
;
571 bzero(result
, sizeof(*result
));
573 if (!OSCompareAndSwapPtr(NULL
, result
, &rte
->rt_stats
))
575 nstat_free_aligned(result
, nstat_malloc_tag
);
576 result
= rte
->rt_stats
;
582 __private_extern__
void
588 nstat_free_aligned(rte
->rt_stats
, nstat_malloc_tag
);
589 rte
->rt_stats
= NULL
;
593 __private_extern__
void
594 nstat_route_connect_attempt(
599 struct nstat_counts
* stats
= nstat_route_attach(rte
);
602 OSIncrementAtomic(&stats
->nstat_connectattempts
);
605 rte
= rte
->rt_parent
;
609 __private_extern__
void
610 nstat_route_connect_success(
616 struct nstat_counts
* stats
= nstat_route_attach(rte
);
619 OSIncrementAtomic(&stats
->nstat_connectsuccesses
);
622 rte
= rte
->rt_parent
;
626 __private_extern__
void
635 struct nstat_counts
* stats
= nstat_route_attach(rte
);
638 if ((flags
& NSTAT_TX_FLAG_RETRANSMIT
) != 0)
640 OSAddAtomic(bytes
, &stats
->nstat_txretransmit
);
644 OSAddAtomic64((SInt64
)packets
, (SInt64
*)&stats
->nstat_txpackets
);
645 OSAddAtomic64((SInt64
)bytes
, (SInt64
*)&stats
->nstat_txbytes
);
649 rte
= rte
->rt_parent
;
653 __private_extern__
void
662 struct nstat_counts
* stats
= nstat_route_attach(rte
);
667 OSAddAtomic64((SInt64
)packets
, (SInt64
*)&stats
->nstat_rxpackets
);
668 OSAddAtomic64((SInt64
)bytes
, (SInt64
*)&stats
->nstat_rxbytes
);
672 if (flags
& NSTAT_RX_FLAG_OUT_OF_ORDER
)
673 OSAddAtomic(bytes
, &stats
->nstat_rxoutoforderbytes
);
674 if (flags
& NSTAT_RX_FLAG_DUPLICATE
)
675 OSAddAtomic(bytes
, &stats
->nstat_rxduplicatebytes
);
679 rte
= rte
->rt_parent
;
683 __private_extern__
void
689 const int32_t factor
= 8;
693 struct nstat_counts
* stats
= nstat_route_attach(rte
);
702 oldrtt
= stats
->nstat_avg_rtt
;
709 newrtt
= oldrtt
- (oldrtt
- (int32_t)rtt
) / factor
;
711 if (oldrtt
== newrtt
) break;
712 } while (!OSCompareAndSwap(oldrtt
, newrtt
, &stats
->nstat_avg_rtt
));
717 oldrtt
= stats
->nstat_min_rtt
;
718 if (oldrtt
!= 0 && oldrtt
< (int32_t)rtt
)
722 } while (!OSCompareAndSwap(oldrtt
, rtt
, &stats
->nstat_min_rtt
));
727 oldrtt
= stats
->nstat_var_rtt
;
734 newrtt
= oldrtt
- (oldrtt
- (int32_t)rtt_var
) / factor
;
736 if (oldrtt
== newrtt
) break;
737 } while (!OSCompareAndSwap(oldrtt
, newrtt
, &stats
->nstat_var_rtt
));
740 rte
= rte
->rt_parent
;
745 #pragma mark -- TCP Provider --
748 * Due to the way the kernel deallocates a process (the process structure
749 * might be gone by the time we get the PCB detach notification),
750 * we need to cache the process name. Without this, proc_name() would
751 * return null and the process name would never be sent to userland.
753 struct nstat_tcpudp_cookie
{
755 char pname
[MAXCOMLEN
+1];
758 static struct nstat_tcpudp_cookie
*
759 nstat_tcpudp_cookie_alloc(
763 struct nstat_tcpudp_cookie
*cookie
;
765 cookie
= OSMalloc(sizeof(*cookie
), nstat_malloc_tag
);
768 if (ref
&& in_pcb_checkstate(inp
, WNT_ACQUIRE
, 0) == WNT_STOPUSING
)
770 OSFree(cookie
, sizeof(*cookie
), nstat_malloc_tag
);
773 bzero(cookie
, sizeof(*cookie
));
775 proc_name(inp
->inp_socket
->last_pid
, cookie
->pname
,
776 sizeof(cookie
->pname
));
782 nstat_tcpudp_cookie_release(
783 struct nstat_tcpudp_cookie
*cookie
,
786 in_pcb_checkstate(cookie
->inp
, WNT_RELEASE
, inplock
);
787 OSFree(cookie
, sizeof(*cookie
), nstat_malloc_tag
);
790 static nstat_provider nstat_tcp_provider
;
794 struct inpcbinfo
*inpinfo
,
797 nstat_provider_cookie_t
*out_cookie
)
799 struct inpcb
*inp
= NULL
;
801 // parameter validation
802 const nstat_tcp_add_param
*param
= (const nstat_tcp_add_param
*)data
;
803 if (length
< sizeof(*param
))
808 // src and dst must match
809 if (param
->remote
.v4
.sin_family
!= 0 &&
810 param
->remote
.v4
.sin_family
!= param
->local
.v4
.sin_family
)
816 switch (param
->local
.v4
.sin_family
)
820 if (param
->local
.v4
.sin_len
!= sizeof(param
->local
.v4
) ||
821 (param
->remote
.v4
.sin_family
!= 0 &&
822 param
->remote
.v4
.sin_len
!= sizeof(param
->remote
.v4
)))
827 inp
= in_pcblookup_hash(inpinfo
, param
->remote
.v4
.sin_addr
, param
->remote
.v4
.sin_port
,
828 param
->local
.v4
.sin_addr
, param
->local
.v4
.sin_port
, 1, NULL
);
837 const struct in6_addr
*in6c
;
838 struct in6_addr
*in6
;
841 if (param
->local
.v6
.sin6_len
!= sizeof(param
->local
.v6
) ||
842 (param
->remote
.v6
.sin6_family
!= 0 &&
843 param
->remote
.v6
.sin6_len
!= sizeof(param
->remote
.v6
)))
848 local
.in6c
= ¶m
->local
.v6
.sin6_addr
;
849 remote
.in6c
= ¶m
->remote
.v6
.sin6_addr
;
851 inp
= in6_pcblookup_hash(inpinfo
, remote
.in6
, param
->remote
.v6
.sin6_port
,
852 local
.in6
, param
->local
.v6
.sin6_port
, 1, NULL
);
864 // At this point we have a ref to the inpcb
865 *out_cookie
= nstat_tcpudp_cookie_alloc(inp
, false);
866 if (*out_cookie
== NULL
)
867 in_pcb_checkstate(inp
, WNT_RELEASE
, 0);
876 nstat_provider_cookie_t
*out_cookie
)
878 return nstat_tcpudp_lookup(&tcbinfo
, data
, length
, out_cookie
);
883 nstat_provider_cookie_t cookie
)
885 struct nstat_tcpudp_cookie
*tucookie
=
886 (struct nstat_tcpudp_cookie
*)cookie
;
890 return (!(inp
= tucookie
->inp
) ||
891 !(tp
= intotcpcb(inp
)) ||
892 inp
->inp_state
== INPCB_STATE_DEAD
||
893 tp
->t_state
== TCPS_TIME_WAIT
) ? 1 : 0;
898 nstat_provider_cookie_t cookie
,
899 struct nstat_counts
*out_counts
,
902 struct nstat_tcpudp_cookie
*tucookie
=
903 (struct nstat_tcpudp_cookie
*)cookie
;
906 bzero(out_counts
, sizeof(*out_counts
));
910 // if the pcb is in the dead state, we should stop using it
911 if (nstat_tcp_gone(cookie
))
914 if (!(inp
= tucookie
->inp
) || !intotcpcb(inp
))
918 struct tcpcb
*tp
= intotcpcb(inp
);
920 atomic_get_64(out_counts
->nstat_rxpackets
, &inp
->inp_stat
->rxpackets
);
921 atomic_get_64(out_counts
->nstat_rxbytes
, &inp
->inp_stat
->rxbytes
);
922 atomic_get_64(out_counts
->nstat_txpackets
, &inp
->inp_stat
->txpackets
);
923 atomic_get_64(out_counts
->nstat_txbytes
, &inp
->inp_stat
->txbytes
);
924 out_counts
->nstat_rxduplicatebytes
= tp
->t_stat
.rxduplicatebytes
;
925 out_counts
->nstat_rxoutoforderbytes
= tp
->t_stat
.rxoutoforderbytes
;
926 out_counts
->nstat_txretransmit
= tp
->t_stat
.txretransmitbytes
;
927 out_counts
->nstat_connectattempts
= tp
->t_state
>= TCPS_SYN_SENT
? 1 : 0;
928 out_counts
->nstat_connectsuccesses
= tp
->t_state
>= TCPS_ESTABLISHED
? 1 : 0;
929 out_counts
->nstat_avg_rtt
= tp
->t_srtt
;
930 out_counts
->nstat_min_rtt
= tp
->t_rttbest
;
931 out_counts
->nstat_var_rtt
= tp
->t_rttvar
;
932 if (out_counts
->nstat_avg_rtt
< out_counts
->nstat_min_rtt
)
933 out_counts
->nstat_min_rtt
= out_counts
->nstat_avg_rtt
;
934 atomic_get_64(out_counts
->nstat_cell_rxbytes
, &inp
->inp_cstat
->rxbytes
);
935 atomic_get_64(out_counts
->nstat_cell_txbytes
, &inp
->inp_cstat
->txbytes
);
936 atomic_get_64(out_counts
->nstat_wifi_rxbytes
, &inp
->inp_wstat
->rxbytes
);
937 atomic_get_64(out_counts
->nstat_wifi_txbytes
, &inp
->inp_wstat
->txbytes
);
944 nstat_provider_cookie_t cookie
,
947 struct nstat_tcpudp_cookie
*tucookie
=
948 (struct nstat_tcpudp_cookie
*)cookie
;
950 nstat_tcpudp_cookie_release(tucookie
, locked
);
954 nstat_tcp_add_watcher(
955 nstat_control_state
*state
)
957 OSIncrementAtomic(&nstat_tcp_watchers
);
959 lck_rw_lock_shared(tcbinfo
.ipi_lock
);
961 // Add all current tcp inpcbs. Ignore those in timewait
963 struct nstat_tcpudp_cookie
*cookie
;
964 for (inp
= LIST_FIRST(tcbinfo
.ipi_listhead
); inp
; inp
= LIST_NEXT(inp
, inp_list
))
966 cookie
= nstat_tcpudp_cookie_alloc(inp
, true);
969 if (nstat_control_source_add(0, state
, &nstat_tcp_provider
,
972 nstat_tcpudp_cookie_release(cookie
, false);
977 lck_rw_done(tcbinfo
.ipi_lock
);
983 nstat_tcp_remove_watcher(
984 __unused nstat_control_state
*state
)
986 OSDecrementAtomic(&nstat_tcp_watchers
);
989 __private_extern__
void
993 struct nstat_tcpudp_cookie
*cookie
;
995 if (nstat_tcp_watchers
== 0)
998 lck_mtx_lock(&nstat_mtx
);
999 nstat_control_state
*state
;
1000 for (state
= nstat_controls
; state
; state
= state
->ncs_next
)
1002 if ((state
->ncs_watching
& (1 << NSTAT_PROVIDER_TCP
)) != 0)
1004 // this client is watching tcp
1005 // acquire a reference for it
1006 cookie
= nstat_tcpudp_cookie_alloc(inp
, true);
1009 // add the source, if that fails, release the reference
1010 if (nstat_control_source_add(0, state
,
1011 &nstat_tcp_provider
, cookie
) != 0)
1013 nstat_tcpudp_cookie_release(cookie
, false);
1018 lck_mtx_unlock(&nstat_mtx
);
1021 __private_extern__
void
1022 nstat_pcb_detach(struct inpcb
*inp
)
1024 nstat_control_state
*state
;
1025 nstat_src
*src
, *prevsrc
;
1026 nstat_src
*dead_list
= NULL
;
1027 struct nstat_tcpudp_cookie
*tucookie
;
1029 if (inp
== NULL
|| (nstat_tcp_watchers
== 0 && nstat_udp_watchers
== 0))
1032 lck_mtx_lock(&nstat_mtx
);
1033 for (state
= nstat_controls
; state
; state
= state
->ncs_next
) {
1034 lck_mtx_lock(&state
->mtx
);
1035 for (prevsrc
= NULL
, src
= state
->ncs_srcs
; src
;
1036 prevsrc
= src
, src
= src
->next
)
1038 tucookie
= (struct nstat_tcpudp_cookie
*)src
->cookie
;
1039 if (tucookie
->inp
== inp
)
1044 // send one last counts notification
1045 nstat_control_send_counts(state
, src
, 0, NULL
);
1047 // send a last description
1048 nstat_control_send_description(state
, src
, 0);
1050 // send the source removed notification
1051 nstat_control_send_removed(state
, src
);
1054 prevsrc
->next
= src
->next
;
1056 state
->ncs_srcs
= src
->next
;
1058 src
->next
= dead_list
;
1061 lck_mtx_unlock(&state
->mtx
);
1063 lck_mtx_unlock(&nstat_mtx
);
1067 dead_list
= src
->next
;
1069 nstat_control_cleanup_source(NULL
, src
, TRUE
);
1074 nstat_tcp_copy_descriptor(
1075 nstat_provider_cookie_t cookie
,
1079 if (len
< sizeof(nstat_tcp_descriptor
))
1084 if (nstat_tcp_gone(cookie
))
1087 nstat_tcp_descriptor
*desc
= (nstat_tcp_descriptor
*)data
;
1088 struct nstat_tcpudp_cookie
*tucookie
=
1089 (struct nstat_tcpudp_cookie
*)cookie
;
1090 struct inpcb
*inp
= tucookie
->inp
;
1091 struct tcpcb
*tp
= intotcpcb(inp
);
1092 bzero(desc
, sizeof(*desc
));
1094 if (inp
->inp_vflag
& INP_IPV6
)
1096 nstat_ip6_to_sockaddr(&inp
->in6p_laddr
, inp
->inp_lport
,
1097 &desc
->local
.v6
, sizeof(desc
->local
));
1098 nstat_ip6_to_sockaddr(&inp
->in6p_faddr
, inp
->inp_fport
,
1099 &desc
->remote
.v6
, sizeof(desc
->remote
));
1101 else if (inp
->inp_vflag
& INP_IPV4
)
1103 nstat_ip_to_sockaddr(&inp
->inp_laddr
, inp
->inp_lport
,
1104 &desc
->local
.v4
, sizeof(desc
->local
));
1105 nstat_ip_to_sockaddr(&inp
->inp_faddr
, inp
->inp_fport
,
1106 &desc
->remote
.v4
, sizeof(desc
->remote
));
1109 desc
->state
= intotcpcb(inp
)->t_state
;
1110 desc
->ifindex
= (inp
->inp_last_outifp
== NULL
) ? 0 :
1111 inp
->inp_last_outifp
->if_index
;
1113 // danger - not locked, values could be bogus
1114 desc
->txunacked
= tp
->snd_max
- tp
->snd_una
;
1115 desc
->txwindow
= tp
->snd_wnd
;
1116 desc
->txcwindow
= tp
->snd_cwnd
;
1118 struct socket
*so
= inp
->inp_socket
;
1121 // TBD - take the socket lock around these to make sure
1123 desc
->upid
= so
->last_upid
;
1124 desc
->pid
= so
->last_pid
;
1125 desc
->traffic_class
= so
->so_traffic_class
;
1126 proc_name(desc
->pid
, desc
->pname
, sizeof(desc
->pname
));
1127 if (desc
->pname
== NULL
|| desc
->pname
[0] == 0)
1129 strlcpy(desc
->pname
, tucookie
->pname
,
1130 sizeof(desc
->pname
));
1134 desc
->pname
[sizeof(desc
->pname
) - 1] = 0;
1135 strlcpy(tucookie
->pname
, desc
->pname
,
1136 sizeof(tucookie
->pname
));
1138 memcpy(desc
->uuid
, so
->last_uuid
, sizeof(so
->last_uuid
));
1139 if (so
->so_flags
& SOF_DELEGATED
) {
1140 desc
->eupid
= so
->e_upid
;
1141 desc
->epid
= so
->e_pid
;
1142 memcpy(desc
->euuid
, so
->e_uuid
, sizeof(so
->e_uuid
));
1144 desc
->eupid
= desc
->upid
;
1145 desc
->epid
= desc
->pid
;
1146 memcpy(desc
->euuid
, desc
->uuid
, sizeof(desc
->uuid
));
1148 desc
->sndbufsize
= so
->so_snd
.sb_hiwat
;
1149 desc
->sndbufused
= so
->so_snd
.sb_cc
;
1150 desc
->rcvbufsize
= so
->so_rcv
.sb_hiwat
;
1151 desc
->rcvbufused
= so
->so_rcv
.sb_cc
;
1158 nstat_init_tcp_provider(void)
1160 bzero(&nstat_tcp_provider
, sizeof(nstat_tcp_provider
));
1161 nstat_tcp_provider
.nstat_descriptor_length
= sizeof(nstat_tcp_descriptor
);
1162 nstat_tcp_provider
.nstat_provider_id
= NSTAT_PROVIDER_TCP
;
1163 nstat_tcp_provider
.nstat_lookup
= nstat_tcp_lookup
;
1164 nstat_tcp_provider
.nstat_gone
= nstat_tcp_gone
;
1165 nstat_tcp_provider
.nstat_counts
= nstat_tcp_counts
;
1166 nstat_tcp_provider
.nstat_release
= nstat_tcp_release
;
1167 nstat_tcp_provider
.nstat_watcher_add
= nstat_tcp_add_watcher
;
1168 nstat_tcp_provider
.nstat_watcher_remove
= nstat_tcp_remove_watcher
;
1169 nstat_tcp_provider
.nstat_copy_descriptor
= nstat_tcp_copy_descriptor
;
1170 nstat_tcp_provider
.next
= nstat_providers
;
1171 nstat_providers
= &nstat_tcp_provider
;
1174 #pragma mark -- UDP Provider --
1176 static nstat_provider nstat_udp_provider
;
1182 nstat_provider_cookie_t
*out_cookie
)
1184 return nstat_tcpudp_lookup(&udbinfo
, data
, length
, out_cookie
);
1189 nstat_provider_cookie_t cookie
)
1191 struct nstat_tcpudp_cookie
*tucookie
=
1192 (struct nstat_tcpudp_cookie
*)cookie
;
1195 return (!(inp
= tucookie
->inp
) ||
1196 inp
->inp_state
== INPCB_STATE_DEAD
) ? 1 : 0;
1201 nstat_provider_cookie_t cookie
,
1202 struct nstat_counts
*out_counts
,
1205 struct nstat_tcpudp_cookie
*tucookie
=
1206 (struct nstat_tcpudp_cookie
*)cookie
;
1210 // if the pcb is in the dead state, we should stop using it
1211 if (nstat_udp_gone(cookie
))
1217 struct inpcb
*inp
= tucookie
->inp
;
1219 atomic_get_64(out_counts
->nstat_rxpackets
, &inp
->inp_stat
->rxpackets
);
1220 atomic_get_64(out_counts
->nstat_rxbytes
, &inp
->inp_stat
->rxbytes
);
1221 atomic_get_64(out_counts
->nstat_txpackets
, &inp
->inp_stat
->txpackets
);
1222 atomic_get_64(out_counts
->nstat_txbytes
, &inp
->inp_stat
->txbytes
);
1223 atomic_get_64(out_counts
->nstat_cell_rxbytes
, &inp
->inp_cstat
->rxbytes
);
1224 atomic_get_64(out_counts
->nstat_cell_txbytes
, &inp
->inp_cstat
->txbytes
);
1225 atomic_get_64(out_counts
->nstat_wifi_rxbytes
, &inp
->inp_wstat
->rxbytes
);
1226 atomic_get_64(out_counts
->nstat_wifi_txbytes
, &inp
->inp_wstat
->txbytes
);
1233 nstat_provider_cookie_t cookie
,
1236 struct nstat_tcpudp_cookie
*tucookie
=
1237 (struct nstat_tcpudp_cookie
*)cookie
;
1239 nstat_tcpudp_cookie_release(tucookie
, locked
);
1243 nstat_udp_add_watcher(
1244 nstat_control_state
*state
)
1247 struct nstat_tcpudp_cookie
*cookie
;
1249 OSIncrementAtomic(&nstat_udp_watchers
);
1251 lck_rw_lock_shared(udbinfo
.ipi_lock
);
1252 // Add all current UDP inpcbs.
1253 for (inp
= LIST_FIRST(udbinfo
.ipi_listhead
); inp
; inp
= LIST_NEXT(inp
, inp_list
))
1255 cookie
= nstat_tcpudp_cookie_alloc(inp
, true);
1258 if (nstat_control_source_add(0, state
, &nstat_udp_provider
,
1261 nstat_tcpudp_cookie_release(cookie
, false);
1266 lck_rw_done(udbinfo
.ipi_lock
);
1272 nstat_udp_remove_watcher(
1273 __unused nstat_control_state
*state
)
1275 OSDecrementAtomic(&nstat_udp_watchers
);
1278 __private_extern__
void
1282 struct nstat_tcpudp_cookie
*cookie
;
1284 if (nstat_udp_watchers
== 0)
1287 lck_mtx_lock(&nstat_mtx
);
1288 nstat_control_state
*state
;
1289 for (state
= nstat_controls
; state
; state
= state
->ncs_next
)
1291 if ((state
->ncs_watching
& (1 << NSTAT_PROVIDER_UDP
)) != 0)
1293 // this client is watching tcp
1294 // acquire a reference for it
1295 cookie
= nstat_tcpudp_cookie_alloc(inp
, true);
1298 // add the source, if that fails, release the reference
1299 if (nstat_control_source_add(0, state
,
1300 &nstat_udp_provider
, cookie
) != 0)
1302 nstat_tcpudp_cookie_release(cookie
, false);
1307 lck_mtx_unlock(&nstat_mtx
);
1311 nstat_udp_copy_descriptor(
1312 nstat_provider_cookie_t cookie
,
1316 if (len
< sizeof(nstat_udp_descriptor
))
1321 if (nstat_udp_gone(cookie
))
1324 struct nstat_tcpudp_cookie
*tucookie
=
1325 (struct nstat_tcpudp_cookie
*)cookie
;
1326 nstat_udp_descriptor
*desc
= (nstat_udp_descriptor
*)data
;
1327 struct inpcb
*inp
= tucookie
->inp
;
1329 bzero(desc
, sizeof(*desc
));
1331 if (inp
->inp_vflag
& INP_IPV6
)
1333 nstat_ip6_to_sockaddr(&inp
->in6p_laddr
, inp
->inp_lport
,
1334 &desc
->local
.v6
, sizeof(desc
->local
));
1335 nstat_ip6_to_sockaddr(&inp
->in6p_faddr
, inp
->inp_fport
,
1336 &desc
->remote
.v6
, sizeof(desc
->remote
));
1338 else if (inp
->inp_vflag
& INP_IPV4
)
1340 nstat_ip_to_sockaddr(&inp
->inp_laddr
, inp
->inp_lport
,
1341 &desc
->local
.v4
, sizeof(desc
->local
));
1342 nstat_ip_to_sockaddr(&inp
->inp_faddr
, inp
->inp_fport
,
1343 &desc
->remote
.v4
, sizeof(desc
->remote
));
1346 desc
->ifindex
= (inp
->inp_last_outifp
== NULL
) ? 0 :
1347 inp
->inp_last_outifp
->if_index
;
1349 struct socket
*so
= inp
->inp_socket
;
1352 // TBD - take the socket lock around these to make sure
1354 desc
->upid
= so
->last_upid
;
1355 desc
->pid
= so
->last_pid
;
1356 proc_name(desc
->pid
, desc
->pname
, sizeof(desc
->pname
));
1357 if (desc
->pname
== NULL
|| desc
->pname
[0] == 0)
1359 strlcpy(desc
->pname
, tucookie
->pname
,
1360 sizeof(desc
->pname
));
1364 desc
->pname
[sizeof(desc
->pname
) - 1] = 0;
1365 strlcpy(tucookie
->pname
, desc
->pname
,
1366 sizeof(tucookie
->pname
));
1368 memcpy(desc
->uuid
, so
->last_uuid
, sizeof(so
->last_uuid
));
1369 if (so
->so_flags
& SOF_DELEGATED
) {
1370 desc
->eupid
= so
->e_upid
;
1371 desc
->epid
= so
->e_pid
;
1372 memcpy(desc
->euuid
, so
->e_uuid
, sizeof(so
->e_uuid
));
1374 desc
->eupid
= desc
->upid
;
1375 desc
->epid
= desc
->pid
;
1376 memcpy(desc
->euuid
, desc
->uuid
, sizeof(desc
->uuid
));
1378 desc
->rcvbufsize
= so
->so_rcv
.sb_hiwat
;
1379 desc
->rcvbufused
= so
->so_rcv
.sb_cc
;
1380 desc
->traffic_class
= so
->so_traffic_class
;
1387 nstat_init_udp_provider(void)
1389 bzero(&nstat_udp_provider
, sizeof(nstat_udp_provider
));
1390 nstat_udp_provider
.nstat_provider_id
= NSTAT_PROVIDER_UDP
;
1391 nstat_udp_provider
.nstat_descriptor_length
= sizeof(nstat_udp_descriptor
);
1392 nstat_udp_provider
.nstat_lookup
= nstat_udp_lookup
;
1393 nstat_udp_provider
.nstat_gone
= nstat_udp_gone
;
1394 nstat_udp_provider
.nstat_counts
= nstat_udp_counts
;
1395 nstat_udp_provider
.nstat_watcher_add
= nstat_udp_add_watcher
;
1396 nstat_udp_provider
.nstat_watcher_remove
= nstat_udp_remove_watcher
;
1397 nstat_udp_provider
.nstat_copy_descriptor
= nstat_udp_copy_descriptor
;
1398 nstat_udp_provider
.nstat_release
= nstat_udp_release
;
1399 nstat_udp_provider
.next
= nstat_providers
;
1400 nstat_providers
= &nstat_udp_provider
;
1403 #pragma mark -- ifnet Provider --
1405 static nstat_provider nstat_ifnet_provider
;
1408 * We store a pointer to the ifnet and the original threshold
1409 * requested by the client.
1411 struct nstat_ifnet_cookie
1421 nstat_provider_cookie_t
*out_cookie
)
1423 const nstat_ifnet_add_param
*param
= (nstat_ifnet_add_param
*)data
;
1425 boolean_t changed
= FALSE
;
1426 nstat_control_state
*state
;
1428 struct nstat_ifnet_cookie
*cookie
;
1430 if (length
< sizeof(*param
) || param
->threshold
< 1024*1024)
1432 if (nstat_privcheck
!= 0) {
1433 errno_t result
= priv_check_cred(kauth_cred_get(),
1434 PRIV_NET_PRIVILEGED_NETWORK_STATISTICS
, 0);
1438 cookie
= OSMalloc(sizeof(*cookie
), nstat_malloc_tag
);
1441 bzero(cookie
, sizeof(*cookie
));
1443 ifnet_head_lock_shared();
1444 TAILQ_FOREACH(ifp
, &ifnet_head
, if_link
)
1446 ifnet_lock_exclusive(ifp
);
1447 if (ifp
->if_index
== param
->ifindex
)
1450 cookie
->threshold
= param
->threshold
;
1451 *out_cookie
= cookie
;
1452 if (!ifp
->if_data_threshold
||
1453 ifp
->if_data_threshold
> param
->threshold
)
1456 ifp
->if_data_threshold
= param
->threshold
;
1458 ifnet_lock_done(ifp
);
1459 ifnet_reference(ifp
);
1462 ifnet_lock_done(ifp
);
1467 * When we change the threshold to something smaller, we notify
1468 * all of our clients with a description message.
1469 * We won't send a message to the client we are currently serving
1470 * because it has no `ifnet source' yet.
1474 lck_mtx_lock(&nstat_mtx
);
1475 for (state
= nstat_controls
; state
; state
= state
->ncs_next
)
1477 lck_mtx_lock(&state
->mtx
);
1478 for (src
= state
->ncs_srcs
; src
; src
= src
->next
)
1480 if (src
->provider
!= &nstat_ifnet_provider
)
1482 nstat_control_send_description(state
, src
, 0);
1484 lck_mtx_unlock(&state
->mtx
);
1486 lck_mtx_unlock(&nstat_mtx
);
1488 if (cookie
->ifp
== NULL
)
1489 OSFree(cookie
, sizeof(*cookie
), nstat_malloc_tag
);
1491 return ifp
? 0 : EINVAL
;
1496 nstat_provider_cookie_t cookie
)
1499 struct nstat_ifnet_cookie
*ifcookie
=
1500 (struct nstat_ifnet_cookie
*)cookie
;
1502 ifnet_head_lock_shared();
1503 TAILQ_FOREACH(ifp
, &ifnet_head
, if_link
)
1505 if (ifp
== ifcookie
->ifp
)
1515 nstat_provider_cookie_t cookie
,
1516 struct nstat_counts
*out_counts
,
1519 struct nstat_ifnet_cookie
*ifcookie
=
1520 (struct nstat_ifnet_cookie
*)cookie
;
1521 struct ifnet
*ifp
= ifcookie
->ifp
;
1525 // if the ifnet is gone, we should stop using it
1526 if (nstat_ifnet_gone(cookie
))
1532 bzero(out_counts
, sizeof(*out_counts
));
1533 out_counts
->nstat_rxpackets
= ifp
->if_ipackets
;
1534 out_counts
->nstat_rxbytes
= ifp
->if_ibytes
;
1535 out_counts
->nstat_txpackets
= ifp
->if_opackets
;
1536 out_counts
->nstat_txbytes
= ifp
->if_obytes
;
1537 out_counts
->nstat_cell_rxbytes
= out_counts
->nstat_cell_txbytes
= 0;
1543 nstat_ifnet_release(
1544 nstat_provider_cookie_t cookie
,
1545 __unused
int locked
)
1547 struct nstat_ifnet_cookie
*ifcookie
;
1549 nstat_control_state
*state
;
1551 uint64_t minthreshold
= UINT64_MAX
;
1554 * Find all the clients that requested a threshold
1555 * for this ifnet and re-calculate if_data_threshold.
1557 lck_mtx_lock(&nstat_mtx
);
1558 for (state
= nstat_controls
; state
; state
= state
->ncs_next
)
1560 lck_mtx_lock(&state
->mtx
);
1561 for (src
= state
->ncs_srcs
; src
; src
= src
->next
)
1563 /* Skip the provider we are about to detach. */
1564 if (src
->provider
!= &nstat_ifnet_provider
||
1565 src
->cookie
== cookie
)
1567 ifcookie
= (struct nstat_ifnet_cookie
*)src
->cookie
;
1568 if (ifcookie
->threshold
< minthreshold
)
1569 minthreshold
= ifcookie
->threshold
;
1571 lck_mtx_unlock(&state
->mtx
);
1573 lck_mtx_unlock(&nstat_mtx
);
1575 * Reset if_data_threshold or disable it.
1577 ifcookie
= (struct nstat_ifnet_cookie
*)cookie
;
1578 ifp
= ifcookie
->ifp
;
1579 if (ifnet_is_attached(ifp
, 1)) {
1580 ifnet_lock_exclusive(ifp
);
1581 if (minthreshold
== UINT64_MAX
)
1582 ifp
->if_data_threshold
= 0;
1584 ifp
->if_data_threshold
= minthreshold
;
1585 ifnet_lock_done(ifp
);
1586 ifnet_decr_iorefcnt(ifp
);
1589 OSFree(ifcookie
, sizeof(*ifcookie
), nstat_malloc_tag
);
1593 nstat_ifnet_copy_descriptor(
1594 nstat_provider_cookie_t cookie
,
1598 nstat_ifnet_descriptor
*desc
= (nstat_ifnet_descriptor
*)data
;
1599 struct nstat_ifnet_cookie
*ifcookie
=
1600 (struct nstat_ifnet_cookie
*)cookie
;
1601 struct ifnet
*ifp
= ifcookie
->ifp
;
1603 if (len
< sizeof(nstat_ifnet_descriptor
))
1606 if (nstat_ifnet_gone(cookie
))
1609 bzero(desc
, sizeof(*desc
));
1610 ifnet_lock_shared(ifp
);
1611 strlcpy(desc
->name
, ifp
->if_xname
, sizeof(desc
->name
));
1612 desc
->ifindex
= ifp
->if_index
;
1613 desc
->threshold
= ifp
->if_data_threshold
;
1614 desc
->type
= ifp
->if_type
;
1615 if (ifp
->if_desc
.ifd_len
< sizeof(desc
->description
))
1616 memcpy(desc
->description
, ifp
->if_desc
.ifd_desc
,
1617 sizeof(desc
->description
));
1618 ifnet_lock_done(ifp
);
1624 nstat_init_ifnet_provider(void)
1626 bzero(&nstat_ifnet_provider
, sizeof(nstat_ifnet_provider
));
1627 nstat_ifnet_provider
.nstat_provider_id
= NSTAT_PROVIDER_IFNET
;
1628 nstat_ifnet_provider
.nstat_descriptor_length
= sizeof(nstat_ifnet_descriptor
);
1629 nstat_ifnet_provider
.nstat_lookup
= nstat_ifnet_lookup
;
1630 nstat_ifnet_provider
.nstat_gone
= nstat_ifnet_gone
;
1631 nstat_ifnet_provider
.nstat_counts
= nstat_ifnet_counts
;
1632 nstat_ifnet_provider
.nstat_watcher_add
= NULL
;
1633 nstat_ifnet_provider
.nstat_watcher_remove
= NULL
;
1634 nstat_ifnet_provider
.nstat_copy_descriptor
= nstat_ifnet_copy_descriptor
;
1635 nstat_ifnet_provider
.nstat_release
= nstat_ifnet_release
;
1636 nstat_ifnet_provider
.next
= nstat_providers
;
1637 nstat_providers
= &nstat_ifnet_provider
;
1640 __private_extern__
void
1641 nstat_ifnet_threshold_reached(unsigned int ifindex
)
1643 nstat_control_state
*state
;
1646 struct nstat_ifnet_cookie
*ifcookie
;
1648 lck_mtx_lock(&nstat_mtx
);
1649 for (state
= nstat_controls
; state
; state
= state
->ncs_next
)
1651 lck_mtx_lock(&state
->mtx
);
1652 for (src
= state
->ncs_srcs
; src
; src
= src
->next
)
1654 if (src
->provider
!= &nstat_ifnet_provider
)
1656 ifcookie
= (struct nstat_ifnet_cookie
*)src
->cookie
;
1657 ifp
= ifcookie
->ifp
;
1658 if (ifp
->if_index
!= ifindex
)
1660 nstat_control_send_counts(state
, src
, 0, NULL
);
1662 lck_mtx_unlock(&state
->mtx
);
1664 lck_mtx_unlock(&nstat_mtx
);
1667 #pragma mark -- Kernel Control Socket --
1669 static kern_ctl_ref nstat_ctlref
= NULL
;
1670 static lck_grp_t
*nstat_lck_grp
= NULL
;
1672 static errno_t
nstat_control_connect(kern_ctl_ref kctl
, struct sockaddr_ctl
*sac
, void **uinfo
);
1673 static errno_t
nstat_control_disconnect(kern_ctl_ref kctl
, u_int32_t unit
, void *uinfo
);
1674 static errno_t
nstat_control_send(kern_ctl_ref kctl
, u_int32_t unit
, void *uinfo
, mbuf_t m
, int flags
);
1680 __unused thread_call_param_t p0
,
1681 __unused thread_call_param_t p1
)
1683 lck_mtx_lock(&nstat_mtx
);
1685 nstat_idle_time
= 0;
1687 nstat_control_state
*control
;
1688 nstat_src
*dead
= NULL
;
1689 nstat_src
*dead_list
= NULL
;
1690 for (control
= nstat_controls
; control
; control
= control
->ncs_next
)
1692 lck_mtx_lock(&control
->mtx
);
1693 nstat_src
**srcpp
= &control
->ncs_srcs
;
1695 if (!(control
->ncs_flags
& NSTAT_FLAG_REQCOUNTS
))
1697 while(*srcpp
!= NULL
)
1699 if ((*srcpp
)->provider
->nstat_gone((*srcpp
)->cookie
))
1701 // Pull it off the list
1703 *srcpp
= (*srcpp
)->next
;
1705 // send one last counts notification
1706 nstat_control_send_counts(control
, dead
,
1709 // send a last description
1710 nstat_control_send_description(control
, dead
, 0);
1712 // send the source removed notification
1713 nstat_control_send_removed(control
, dead
);
1715 // Put this on the list to release later
1716 dead
->next
= dead_list
;
1721 srcpp
= &(*srcpp
)->next
;
1725 control
->ncs_flags
&= ~NSTAT_FLAG_REQCOUNTS
;
1726 lck_mtx_unlock(&control
->mtx
);
1731 clock_interval_to_deadline(60, NSEC_PER_SEC
, &nstat_idle_time
);
1732 thread_call_func_delayed((thread_call_func_t
)nstat_idle_check
, NULL
, nstat_idle_time
);
1735 lck_mtx_unlock(&nstat_mtx
);
1737 // Release the sources now that we aren't holding lots of locks
1741 dead_list
= dead
->next
;
1743 nstat_control_cleanup_source(NULL
, dead
, FALSE
);
1750 nstat_control_register(void)
1752 // Create our lock group first
1753 lck_grp_attr_t
*grp_attr
= lck_grp_attr_alloc_init();
1754 lck_grp_attr_setdefault(grp_attr
);
1755 nstat_lck_grp
= lck_grp_alloc_init("network statistics kctl", grp_attr
);
1756 lck_grp_attr_free(grp_attr
);
1758 lck_mtx_init(&nstat_mtx
, nstat_lck_grp
, NULL
);
1760 // Register the control
1761 struct kern_ctl_reg nstat_control
;
1762 bzero(&nstat_control
, sizeof(nstat_control
));
1763 strlcpy(nstat_control
.ctl_name
, NET_STAT_CONTROL_NAME
, sizeof(nstat_control
.ctl_name
));
1764 nstat_control
.ctl_connect
= nstat_control_connect
;
1765 nstat_control
.ctl_disconnect
= nstat_control_disconnect
;
1766 nstat_control
.ctl_send
= nstat_control_send
;
1768 ctl_register(&nstat_control
, &nstat_ctlref
);
1772 nstat_control_cleanup_source(
1773 nstat_control_state
*state
,
1774 struct nstat_src
*src
,
1778 nstat_control_send_removed(state
, src
);
1780 // Cleanup the source if we found it.
1781 src
->provider
->nstat_release(src
->cookie
, locked
);
1782 OSFree(src
, sizeof(*src
), nstat_malloc_tag
);
1786 nstat_control_connect(
1788 struct sockaddr_ctl
*sac
,
1791 nstat_control_state
*state
= OSMalloc(sizeof(*state
), nstat_malloc_tag
);
1792 if (state
== NULL
) return ENOMEM
;
1794 bzero(state
, sizeof(*state
));
1795 lck_mtx_init(&state
->mtx
, nstat_lck_grp
, NULL
);
1796 state
->ncs_kctl
= kctl
;
1797 state
->ncs_unit
= sac
->sc_unit
;
1798 state
->ncs_flags
= NSTAT_FLAG_REQCOUNTS
;
1801 lck_mtx_lock(&nstat_mtx
);
1802 state
->ncs_next
= nstat_controls
;
1803 nstat_controls
= state
;
1805 if (nstat_idle_time
== 0)
1807 clock_interval_to_deadline(60, NSEC_PER_SEC
, &nstat_idle_time
);
1808 thread_call_func_delayed((thread_call_func_t
)nstat_idle_check
, NULL
, nstat_idle_time
);
1811 lck_mtx_unlock(&nstat_mtx
);
1817 nstat_control_disconnect(
1818 __unused kern_ctl_ref kctl
,
1819 __unused u_int32_t unit
,
1823 nstat_control_state
*state
= (nstat_control_state
*)uinfo
;
1825 // pull it out of the global list of states
1826 lck_mtx_lock(&nstat_mtx
);
1827 nstat_control_state
**statepp
;
1828 for (statepp
= &nstat_controls
; *statepp
; statepp
= &(*statepp
)->ncs_next
)
1830 if (*statepp
== state
)
1832 *statepp
= state
->ncs_next
;
1836 lck_mtx_unlock(&nstat_mtx
);
1838 lck_mtx_lock(&state
->mtx
);
1839 // Stop watching for sources
1840 nstat_provider
*provider
;
1841 watching
= state
->ncs_watching
;
1842 state
->ncs_watching
= 0;
1843 for (provider
= nstat_providers
; provider
&& watching
; provider
= provider
->next
)
1845 if ((watching
& (1 << provider
->nstat_provider_id
)) != 0)
1847 watching
&= ~(1 << provider
->nstat_provider_id
);
1848 provider
->nstat_watcher_remove(state
);
1852 // set cleanup flags
1853 state
->ncs_flags
|= NSTAT_FLAG_CLEANUP
;
1855 // Copy out the list of sources
1856 nstat_src
*srcs
= state
->ncs_srcs
;
1857 state
->ncs_srcs
= NULL
;
1858 lck_mtx_unlock(&state
->mtx
);
1864 // pull it out of the list
1869 nstat_control_cleanup_source(NULL
, src
, FALSE
);
1871 lck_mtx_destroy(&state
->mtx
, nstat_lck_grp
);
1872 OSFree(state
, sizeof(*state
), nstat_malloc_tag
);
1877 static nstat_src_ref_t
1878 nstat_control_next_src_ref(
1879 nstat_control_state
*state
)
1882 nstat_src_ref_t toReturn
= NSTAT_SRC_REF_INVALID
;
1884 for (i
= 0; i
< 1000 && toReturn
== NSTAT_SRC_REF_INVALID
; i
++)
1886 if (state
->ncs_next_srcref
== NSTAT_SRC_REF_INVALID
||
1887 state
->ncs_next_srcref
== NSTAT_SRC_REF_ALL
)
1889 state
->ncs_next_srcref
= 1;
1893 for (src
= state
->ncs_srcs
; src
; src
= src
->next
)
1895 if (src
->srcref
== state
->ncs_next_srcref
)
1899 if (src
== NULL
) toReturn
= state
->ncs_next_srcref
;
1900 state
->ncs_next_srcref
++;
1907 nstat_control_send_counts(
1908 nstat_control_state
*state
,
1910 unsigned long long context
,
1913 nstat_msg_src_counts counts
;
1917 counts
.hdr
.type
= NSTAT_MSG_TYPE_SRC_COUNTS
;
1918 counts
.hdr
.context
= context
;
1919 counts
.srcref
= src
->srcref
;
1920 bzero(&counts
.counts
, sizeof(counts
.counts
));
1921 if (src
->provider
->nstat_counts(src
->cookie
, &counts
.counts
,
1923 if ((src
->filter
& NSTAT_FILTER_NOZEROBYTES
) &&
1924 counts
.counts
.nstat_rxbytes
== 0 &&
1925 counts
.counts
.nstat_txbytes
== 0)
1928 result
= ctl_enqueuedata(state
->ncs_kctl
,
1929 state
->ncs_unit
, &counts
, sizeof(counts
),
1938 nstat_control_send_description(
1939 nstat_control_state
*state
,
1943 // Provider doesn't support getting the descriptor? Done.
1944 if (src
->provider
->nstat_descriptor_length
== 0 ||
1945 src
->provider
->nstat_copy_descriptor
== NULL
)
1950 // Allocate storage for the descriptor message
1952 unsigned int one
= 1;
1953 u_int32_t size
= offsetof(nstat_msg_src_description
, data
) + src
->provider
->nstat_descriptor_length
;
1954 if (mbuf_allocpacket(MBUF_WAITOK
, size
, &one
, &msg
) != 0)
1959 nstat_msg_src_description
*desc
= (nstat_msg_src_description
*)mbuf_data(msg
);
1960 mbuf_setlen(msg
, size
);
1961 mbuf_pkthdr_setlen(msg
, mbuf_len(msg
));
1963 // Query the provider for the provider specific bits
1964 errno_t result
= src
->provider
->nstat_copy_descriptor(src
->cookie
, desc
->data
, src
->provider
->nstat_descriptor_length
);
1972 desc
->hdr
.context
= context
;
1973 desc
->hdr
.type
= NSTAT_MSG_TYPE_SRC_DESC
;
1974 desc
->srcref
= src
->srcref
;
1975 desc
->provider
= src
->provider
->nstat_provider_id
;
1977 result
= ctl_enqueuembuf(state
->ncs_kctl
, state
->ncs_unit
, msg
, CTL_DATA_EOR
);
1987 nstat_control_send_removed(
1988 nstat_control_state
*state
,
1991 nstat_msg_src_removed removed
;
1994 removed
.hdr
.type
= NSTAT_MSG_TYPE_SRC_REMOVED
;
1995 removed
.hdr
.context
= 0;
1996 removed
.srcref
= src
->srcref
;
1997 result
= ctl_enqueuedata(state
->ncs_kctl
, state
->ncs_unit
, &removed
,
1998 sizeof(removed
), CTL_DATA_EOR
);
2004 nstat_control_handle_add_request(
2005 nstat_control_state
*state
,
2010 // Verify the header fits in the first mbuf
2011 if (mbuf_len(m
) < offsetof(nstat_msg_add_src_req
, param
))
2016 // Calculate the length of the parameter field
2017 int32_t paramlength
= mbuf_pkthdr_len(m
) - offsetof(nstat_msg_add_src_req
, param
);
2018 if (paramlength
< 0 || paramlength
> 2 * 1024)
2023 nstat_provider
*provider
;
2024 nstat_provider_cookie_t cookie
;
2025 nstat_msg_add_src_req
*req
= mbuf_data(m
);
2026 if (mbuf_pkthdr_len(m
) > mbuf_len(m
))
2028 // parameter is too large, we need to make a contiguous copy
2029 void *data
= OSMalloc(paramlength
, nstat_malloc_tag
);
2031 if (!data
) return ENOMEM
;
2032 result
= mbuf_copydata(m
, offsetof(nstat_msg_add_src_req
, param
), paramlength
, data
);
2034 result
= nstat_lookup_entry(req
->provider
, data
, paramlength
, &provider
, &cookie
);
2035 OSFree(data
, paramlength
, nstat_malloc_tag
);
2039 result
= nstat_lookup_entry(req
->provider
, (void*)&req
->param
, paramlength
, &provider
, &cookie
);
2047 result
= nstat_control_source_add(req
->hdr
.context
, state
, provider
, cookie
);
2049 provider
->nstat_release(cookie
, 0);
2055 nstat_control_handle_add_all(
2056 nstat_control_state
*state
,
2061 // Verify the header fits in the first mbuf
2062 if (mbuf_len(m
) < sizeof(nstat_msg_add_all_srcs
))
2067 nstat_msg_add_all_srcs
*req
= mbuf_data(m
);
2068 nstat_provider
*provider
= nstat_find_provider_by_id(req
->provider
);
2070 if (!provider
) return ENOENT
;
2071 if (provider
->nstat_watcher_add
== NULL
) return ENOTSUP
;
2073 if (nstat_privcheck
!= 0) {
2074 result
= priv_check_cred(kauth_cred_get(),
2075 PRIV_NET_PRIVILEGED_NETWORK_STATISTICS
, 0);
2080 // Make sure we don't add the provider twice
2081 lck_mtx_lock(&state
->mtx
);
2082 if ((state
->ncs_watching
& (1 << provider
->nstat_provider_id
)) != 0)
2084 state
->ncs_watching
|= (1 << provider
->nstat_provider_id
);
2085 lck_mtx_unlock(&state
->mtx
);
2086 if (result
!= 0) return result
;
2088 result
= provider
->nstat_watcher_add(state
);
2091 lck_mtx_lock(&state
->mtx
);
2092 state
->ncs_watching
&= ~(1 << provider
->nstat_provider_id
);
2093 lck_mtx_unlock(&state
->mtx
);
2098 // Notify the client
2099 nstat_msg_hdr success
;
2100 success
.context
= req
->hdr
.context
;
2101 success
.type
= NSTAT_MSG_TYPE_SUCCESS
;
2103 ctl_enqueuedata(state
->ncs_kctl
, state
->ncs_unit
, &success
, sizeof(success
), CTL_DATA_EOR
);
2110 nstat_control_source_add(
2112 nstat_control_state
*state
,
2113 nstat_provider
*provider
,
2114 nstat_provider_cookie_t cookie
)
2116 // Fill out source added message
2118 unsigned int one
= 1;
2120 if (mbuf_allocpacket(MBUF_WAITOK
, sizeof(nstat_msg_src_added
), &one
, &msg
) != 0)
2123 mbuf_setlen(msg
, sizeof(nstat_msg_src_added
));
2124 mbuf_pkthdr_setlen(msg
, mbuf_len(msg
));
2125 nstat_msg_src_added
*add
= mbuf_data(msg
);
2126 bzero(add
, sizeof(*add
));
2127 add
->hdr
.type
= NSTAT_MSG_TYPE_SRC_ADDED
;
2128 add
->hdr
.context
= context
;
2129 add
->provider
= provider
->nstat_provider_id
;
2131 // Allocate storage for the source
2132 nstat_src
*src
= OSMalloc(sizeof(*src
), nstat_malloc_tag
);
2139 // Fill in the source, including picking an unused source ref
2140 lck_mtx_lock(&state
->mtx
);
2142 add
->srcref
= src
->srcref
= nstat_control_next_src_ref(state
);
2143 if (state
->ncs_flags
& NSTAT_FLAG_CLEANUP
|| src
->srcref
== NSTAT_SRC_REF_INVALID
)
2145 lck_mtx_unlock(&state
->mtx
);
2146 OSFree(src
, sizeof(*src
), nstat_malloc_tag
);
2150 src
->provider
= provider
;
2151 src
->cookie
= cookie
;
2154 // send the source added message
2155 errno_t result
= ctl_enqueuembuf(state
->ncs_kctl
, state
->ncs_unit
, msg
, CTL_DATA_EOR
);
2158 lck_mtx_unlock(&state
->mtx
);
2159 OSFree(src
, sizeof(*src
), nstat_malloc_tag
);
2164 // Put the source in the list
2165 src
->next
= state
->ncs_srcs
;
2166 state
->ncs_srcs
= src
;
2168 // send the description message
2169 // not useful as the source is often not complete
2170 // nstat_control_send_description(state, src, 0);
2172 lck_mtx_unlock(&state
->mtx
);
2178 nstat_control_handle_remove_request(
2179 nstat_control_state
*state
,
2182 nstat_src_ref_t srcref
= NSTAT_SRC_REF_INVALID
;
2184 if (mbuf_copydata(m
, offsetof(nstat_msg_rem_src_req
, srcref
), sizeof(srcref
), &srcref
) != 0)
2189 lck_mtx_lock(&state
->mtx
);
2191 // Remove this source as we look for it
2193 nstat_src
*src
= NULL
;
2194 for (nextp
= &state
->ncs_srcs
; *nextp
; nextp
= &(*nextp
)->next
)
2196 if ((*nextp
)->srcref
== srcref
)
2204 lck_mtx_unlock(&state
->mtx
);
2206 if (src
) nstat_control_cleanup_source(state
, src
, FALSE
);
2208 return src
? 0 : ENOENT
;
2212 nstat_control_handle_query_request(
2213 nstat_control_state
*state
,
2216 // TBD: handle this from another thread so we can enqueue a lot of data
2217 // As written, if a client requests query all, this function will be
2218 // called from their send of the request message. We will attempt to write
2219 // responses and succeed until the buffer fills up. Since the clients thread
2220 // is blocked on send, it won't be reading unless the client has two threads
2221 // using this socket, one for read and one for write. Two threads probably
2222 // won't work with this code anyhow since we don't have proper locking in
2224 nstat_src
*dead_srcs
= NULL
;
2225 errno_t result
= ENOENT
;
2226 nstat_msg_query_src_req req
;
2227 if (mbuf_copydata(m
, 0, sizeof(req
), &req
) != 0)
2232 lck_mtx_lock(&state
->mtx
);
2233 if (req
.srcref
== NSTAT_SRC_REF_ALL
)
2234 state
->ncs_flags
|= NSTAT_FLAG_REQCOUNTS
;
2235 nstat_src
**srcpp
= &state
->ncs_srcs
;
2236 while (*srcpp
!= NULL
)
2241 // XXX ignore IFACE types?
2242 if (req
.srcref
== NSTAT_SRC_REF_ALL
||
2243 (*srcpp
)->srcref
== req
.srcref
)
2245 result
= nstat_control_send_counts(state
, *srcpp
,
2246 req
.hdr
.context
, &gone
);
2248 // If the counts message failed to enqueue then we should clear our flag so
2249 // that a client doesn't miss anything on idle cleanup.
2251 state
->ncs_flags
&= ~NSTAT_FLAG_REQCOUNTS
;
2255 // send one last descriptor message so client may see last state
2257 nstat_control_send_description(state
, *srcpp
,
2260 // pull src out of the list
2261 nstat_src
*src
= *srcpp
;
2264 src
->next
= dead_srcs
;
2268 if (req
.srcref
!= NSTAT_SRC_REF_ALL
)
2273 srcpp
= &(*srcpp
)->next
;
2275 lck_mtx_unlock(&state
->mtx
);
2282 dead_srcs
= src
->next
;
2284 // release src and send notification
2285 nstat_control_cleanup_source(state
, src
, FALSE
);
2288 if (req
.srcref
== NSTAT_SRC_REF_ALL
)
2290 nstat_msg_hdr success
;
2291 success
.context
= req
.hdr
.context
;
2292 success
.type
= NSTAT_MSG_TYPE_SUCCESS
;
2294 ctl_enqueuedata(state
->ncs_kctl
, state
->ncs_unit
, &success
, sizeof(success
), CTL_DATA_EOR
);
2302 nstat_control_handle_get_src_description(
2303 nstat_control_state
*state
,
2306 nstat_msg_get_src_description req
;
2310 if (mbuf_copydata(m
, 0, sizeof(req
), &req
) != 0)
2315 lck_mtx_lock(&state
->mtx
);
2316 if (req
.srcref
== NSTAT_SRC_REF_ALL
)
2317 state
->ncs_flags
|= NSTAT_FLAG_REQDESCS
;
2318 for (src
= state
->ncs_srcs
; src
; src
= src
->next
)
2319 if (req
.srcref
== NSTAT_SRC_REF_ALL
||
2320 src
->srcref
== req
.srcref
)
2322 result
= nstat_control_send_description(state
, src
,
2325 state
->ncs_flags
&= ~NSTAT_FLAG_REQDESCS
;
2326 if (req
.srcref
!= NSTAT_SRC_REF_ALL
)
2329 lck_mtx_unlock(&state
->mtx
);
2330 if (req
.srcref
!= NSTAT_SRC_REF_ALL
&& src
== NULL
)
2332 else if (req
.srcref
== NSTAT_SRC_REF_ALL
)
2334 nstat_msg_hdr success
;
2335 success
.context
= req
.hdr
.context
;
2336 success
.type
= NSTAT_MSG_TYPE_SUCCESS
;
2338 ctl_enqueuedata(state
->ncs_kctl
, state
->ncs_unit
, &success
, sizeof(success
), CTL_DATA_EOR
);
2346 nstat_control_handle_set_filter(
2347 nstat_control_state
*state
,
2350 nstat_msg_set_filter req
;
2353 if (mbuf_copydata(m
, 0, sizeof(req
), &req
) != 0)
2355 if (req
.srcref
== NSTAT_SRC_REF_ALL
||
2356 req
.srcref
== NSTAT_SRC_REF_INVALID
)
2359 lck_mtx_lock(&state
->mtx
);
2360 for (src
= state
->ncs_srcs
; src
; src
= src
->next
)
2361 if (req
.srcref
== src
->srcref
)
2363 src
->filter
= req
.filter
;
2366 lck_mtx_unlock(&state
->mtx
);
2382 nstat_control_state
*state
= (nstat_control_state
*)uinfo
;
2383 struct nstat_msg_hdr
*hdr
;
2384 struct nstat_msg_hdr storage
;
2387 if (mbuf_pkthdr_len(m
) < sizeof(hdr
))
2389 // Is this the right thing to do?
2394 if (mbuf_len(m
) >= sizeof(*hdr
))
2400 mbuf_copydata(m
, 0, sizeof(storage
), &storage
);
2406 case NSTAT_MSG_TYPE_ADD_SRC
:
2407 result
= nstat_control_handle_add_request(state
, m
);
2410 case NSTAT_MSG_TYPE_ADD_ALL_SRCS
:
2411 result
= nstat_control_handle_add_all(state
, m
);
2414 case NSTAT_MSG_TYPE_REM_SRC
:
2415 result
= nstat_control_handle_remove_request(state
, m
);
2418 case NSTAT_MSG_TYPE_QUERY_SRC
:
2419 result
= nstat_control_handle_query_request(state
, m
);
2422 case NSTAT_MSG_TYPE_GET_SRC_DESC
:
2423 result
= nstat_control_handle_get_src_description(state
, m
);
2426 case NSTAT_MSG_TYPE_SET_FILTER
:
2427 result
= nstat_control_handle_set_filter(state
, m
);
2437 struct nstat_msg_error err
;
2439 err
.hdr
.type
= NSTAT_MSG_TYPE_ERROR
;
2440 err
.hdr
.context
= hdr
->context
;
2443 result
= ctl_enqueuedata(kctl
, unit
, &err
, sizeof(err
), CTL_DATA_EOR
);