2 * Copyright (c) 2015-2016 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@
30 #include <sys/systm.h>
31 #include <sys/types.h>
32 #include <sys/queue.h>
33 #include <sys/malloc.h>
34 #include <libkern/OSMalloc.h>
35 #include <sys/kernel.h>
37 #include <sys/domain.h>
38 #include <sys/protosw.h>
39 #include <sys/socket.h>
40 #include <sys/socketvar.h>
41 #include <netinet/ip.h>
42 #include <netinet/ip6.h>
43 #include <netinet/in_pcb.h>
44 #include <net/if_var.h>
45 #include <netinet/tcp_cc.h>
46 #include <net/ntstat.h>
47 #include <sys/kauth.h>
48 #include <sys/sysproto.h>
50 #include <net/network_agent.h>
52 #include <sys/file_internal.h>
54 #include <kern/thread_call.h>
57 * NECP Client Architecture
58 * ------------------------------------------------
59 * See <net/necp.c> for a discussion on NECP database architecture.
61 * Each client of NECP provides a set of parameters for a connection or network state
62 * evaluation, on which NECP policy evaluation is run. This produces a policy result
63 * which can be accessed by the originating process, along with events for when policies
64 * results have changed.
66 * ------------------------------------------------
68 * ------------------------------------------------
69 * A process opens an NECP file descriptor using necp_open(). This is a very simple
70 * file descriptor, upon which the process may do the following operations:
71 * - necp_client_action(...), to add/remove/query clients
72 * - kqueue, to watch for readable events
73 * - close(), to close the client session and release all clients
75 * Client objects are allocated structures that hang off of the file descriptor. Each
77 * - Client ID, a UUID that references the client across the system
78 * - Parameters, a buffer of TLVs that describe the client's connection parameters,
79 * such as the remote and local endpoints, interface requirements, etc.
80 * - Result, a buffer of TLVs containing the current policy evaluation for the client.
81 * This result will be updated whenever a network change occurs that impacts the
82 * policy result for that client.
88 * ==================================
90 * +--------------+ +--------------+ +--------------+
91 * | Client ID | | Client ID | | Client ID |
92 * | ---- | | ---- | | ---- |
93 * | Parameters | | Parameters | | Parameters |
94 * | ---- | | ---- | | ---- |
95 * | Result | | Result | | Result |
96 * +--------------+ +--------------+ +--------------+
98 * ------------------------------------------------
100 * ------------------------------------------------
101 * - Add. Input parameters as a buffer of TLVs, and output a client ID. Allocates a
102 * new client structure on the file descriptor.
103 * - Remove. Input a client ID. Removes a client structure from the file descriptor.
104 * - Copy Parameters. Input a client ID, and output parameter TLVs.
105 * - Copy Result. Input a client ID, and output result TLVs. Alternatively, input empty
106 * client ID and get next unread client result.
107 * - Copy List. List all client IDs.
109 * ------------------------------------------------
110 * Client Policy Evaluation
111 * ------------------------------------------------
112 * Policies are evaluated for clients upon client creation, and upon update events,
113 * which are network/agent/policy changes coalesced by a timer.
115 * The policy evaluation goes through the following steps:
116 * 1. Parse client parameters.
117 * 2. Select a scoped interface if applicable. This involves using require/prohibit
118 * parameters, along with the local address, to select the most appropriate interface
119 * if not explicitly set by the client parameters.
120 * 3. Run NECP application-level policy evalution
121 * 4. Set policy result into client result buffer.
123 * ------------------------------------------------
125 * ------------------------------------------------
126 * If necp_open() is called with the NECP_OPEN_FLAG_OBSERVER flag, and the process
127 * passes the necessary privilege check, the fd is allowed to use necp_client_action()
128 * to copy client state attached to the file descriptors of other processes, and to
129 * list all client IDs on the system.
132 extern u_int32_t necp_debug
;
134 static int noop_read(struct fileproc
*, struct uio
*, int, vfs_context_t
);
135 static int noop_write(struct fileproc
*, struct uio
*, int, vfs_context_t
);
136 static int noop_ioctl(struct fileproc
*, unsigned long, caddr_t
,
138 static int necpop_select(struct fileproc
*, int, void *, vfs_context_t
);
139 static int necpop_close(struct fileglob
*, vfs_context_t
);
140 static int necpop_kqfilter(struct fileproc
*, struct knote
*, vfs_context_t
);
143 static int necp_timeout_microseconds
= 1000 * 100; // 100ms
144 static int necp_timeout_leeway_microseconds
= 1000 * 500; // 500ms
145 extern int tvtohz(struct timeval
*);
148 #define NECP_PARSED_PARAMETERS_FIELD_LOCAL_ADDR 0x0001
149 #define NECP_PARSED_PARAMETERS_FIELD_REMOTE_ADDR 0x0002
150 #define NECP_PARSED_PARAMETERS_FIELD_REQUIRED_IF 0x0004
151 #define NECP_PARSED_PARAMETERS_FIELD_PROHIBITED_IF 0x0008
152 #define NECP_PARSED_PARAMETERS_FIELD_REQUIRED_IFTYPE 0x0010
153 #define NECP_PARSED_PARAMETERS_FIELD_PROHIBITED_IFTYPE 0x0020
154 #define NECP_PARSED_PARAMETERS_FIELD_REQUIRED_AGENT 0x0040
155 #define NECP_PARSED_PARAMETERS_FIELD_PROHIBITED_AGENT 0x0080
156 #define NECP_PARSED_PARAMETERS_FIELD_PREFERRED_AGENT 0x0100
157 #define NECP_PARSED_PARAMETERS_FIELD_REQUIRED_AGENT_TYPE 0x0200
158 #define NECP_PARSED_PARAMETERS_FIELD_PROHIBITED_AGENT_TYPE 0x0400
159 #define NECP_PARSED_PARAMETERS_FIELD_PREFERRED_AGENT_TYPE 0x0800
161 #define NECP_MAX_PARSED_PARAMETERS 16
162 struct necp_client_parsed_parameters
{
163 u_int32_t valid_fields
;
164 union necp_sockaddr_union local_addr
;
165 union necp_sockaddr_union remote_addr
;
166 u_int32_t required_interface_index
;
167 char prohibited_interfaces
[IFXNAMSIZ
][NECP_MAX_PARSED_PARAMETERS
];
168 u_int8_t required_interface_types
[NECP_MAX_PARSED_PARAMETERS
];
169 u_int8_t prohibited_interface_types
[NECP_MAX_PARSED_PARAMETERS
];
170 struct necp_client_parameter_netagent_type required_netagent_types
[NECP_MAX_PARSED_PARAMETERS
];
171 struct necp_client_parameter_netagent_type prohibited_netagent_types
[NECP_MAX_PARSED_PARAMETERS
];
172 struct necp_client_parameter_netagent_type preferred_netagent_types
[NECP_MAX_PARSED_PARAMETERS
];
173 uuid_t required_netagents
[NECP_MAX_PARSED_PARAMETERS
];
174 uuid_t prohibited_netagents
[NECP_MAX_PARSED_PARAMETERS
];
175 uuid_t preferred_netagents
[NECP_MAX_PARSED_PARAMETERS
];
178 static bool necp_find_matching_interface_index(struct necp_client_parsed_parameters
*parsed_parameters
, u_int
*return_ifindex
);
180 static const struct fileops necp_fd_ops
= {
181 .fo_type
= DTYPE_NETPOLICY
,
182 .fo_read
= noop_read
,
183 .fo_write
= noop_write
,
184 .fo_ioctl
= noop_ioctl
,
185 .fo_select
= necpop_select
,
186 .fo_close
= necpop_close
,
187 .fo_kqfilter
= necpop_kqfilter
,
191 struct necp_client_assertion
{
192 LIST_ENTRY(necp_client_assertion
) assertion_chain
;
193 uuid_t asserted_netagent
;
197 LIST_ENTRY(necp_client
) chain
;
201 bool assigned_result_read
;
203 size_t result_length
;
204 u_int8_t result
[NECP_MAX_CLIENT_RESULT_SIZE
];
207 size_t assigned_results_length
;
208 u_int8_t
*assigned_results
;
210 LIST_HEAD(_necp_client_assertion_list
, necp_client_assertion
) assertion_list
;
212 user_addr_t stats_uaddr
;
213 user_size_t stats_ulen
;
214 nstat_userland_context stats_handler_context
;
215 necp_stats_hdr
*stats_area
;
217 size_t parameters_length
;
218 u_int8_t parameters
[0];
221 struct necp_fd_data
{
222 LIST_ENTRY(necp_fd_data
) chain
;
223 LIST_HEAD(_clients
, necp_client
) clients
;
226 decl_lck_mtx_data(, fd_lock
);
230 static LIST_HEAD(_necp_fd_list
, necp_fd_data
) necp_fd_list
;
232 static lck_grp_attr_t
*necp_fd_grp_attr
= NULL
;
233 static lck_attr_t
*necp_fd_mtx_attr
= NULL
;
234 static lck_grp_t
*necp_fd_mtx_grp
= NULL
;
235 decl_lck_rw_data(static, necp_fd_lock
);
237 static thread_call_t necp_client_tcall
;
239 /// NECP file descriptor functions
242 noop_read(struct fileproc
*fp
, struct uio
*uio
, int flags
, vfs_context_t ctx
)
244 #pragma unused(fp, uio, flags, ctx)
249 noop_write(struct fileproc
*fp
, struct uio
*uio
, int flags
,
252 #pragma unused(fp, uio, flags, ctx)
257 noop_ioctl(struct fileproc
*fp
, unsigned long com
, caddr_t data
,
260 #pragma unused(fp, com, data, ctx)
265 necp_fd_notify(struct necp_fd_data
*fd_data
, bool locked
)
267 struct selinfo
*si
= &fd_data
->si
;
270 lck_mtx_lock(&fd_data
->fd_lock
);
275 // use a non-zero hint to tell the notification from the
276 // call done in kqueue_scan() which uses 0
277 KNOTE(&si
->si_note
, 1); // notification
280 lck_mtx_unlock(&fd_data
->fd_lock
);
285 necp_fd_poll(struct necp_fd_data
*fd_data
, int events
, void *wql
, struct proc
*p
, int is_kevent
)
287 #pragma unused(wql, p, is_kevent)
289 struct necp_client
*client
= NULL
;
290 bool has_unread_clients
= FALSE
;
292 u_int want_rx
= events
& (POLLIN
| POLLRDNORM
);
295 LIST_FOREACH(client
, &fd_data
->clients
, chain
) {
296 if (!client
->result_read
|| !client
->assigned_result_read
) {
297 has_unread_clients
= TRUE
;
302 if (has_unread_clients
) {
311 necpop_select(struct fileproc
*fp
, int which
, void *wql
, vfs_context_t ctx
)
313 #pragma unused(fp, which, wql, ctx)
315 struct necp_fd_data
*fd_data
= NULL
;
320 fd_data
= (struct necp_fd_data
*)fp
->f_fglob
->fg_data
;
321 if (fd_data
== NULL
) {
325 procp
= vfs_context_proc(ctx
);
338 lck_mtx_lock(&fd_data
->fd_lock
);
339 revents
= necp_fd_poll(fd_data
, events
, wql
, procp
, 0);
340 lck_mtx_unlock(&fd_data
->fd_lock
);
342 return ((events
& revents
) ? 1 : 0);
346 necp_fd_knrdetach(struct knote
*kn
)
348 struct necp_fd_data
*fd_data
= (struct necp_fd_data
*)kn
->kn_hook
;
349 struct selinfo
*si
= &fd_data
->si
;
351 lck_mtx_lock(&fd_data
->fd_lock
);
352 KNOTE_DETACH(&si
->si_note
, kn
);
353 lck_mtx_unlock(&fd_data
->fd_lock
);
357 necp_fd_knread(struct knote
*kn
, long hint
)
359 #pragma unused(kn, hint)
360 return 1; /* assume we are ready */
364 necp_fd_knrprocess(struct knote
*kn
, struct filt_process_s
*data
, struct kevent_internal_s
*kev
)
367 struct necp_fd_data
*fd_data
;
371 fd_data
= (struct necp_fd_data
*)kn
->kn_hook
;
373 lck_mtx_lock(&fd_data
->fd_lock
);
374 revents
= necp_fd_poll(fd_data
, POLLIN
, NULL
, current_proc(), 1);
375 res
= ((revents
& POLLIN
) != 0);
377 *kev
= kn
->kn_kevent
;
379 lck_mtx_unlock(&fd_data
->fd_lock
);
384 necp_fd_knrtouch(struct knote
*kn
, struct kevent_internal_s
*kev
)
387 struct necp_fd_data
*fd_data
;
390 fd_data
= (struct necp_fd_data
*)kn
->kn_hook
;
392 lck_mtx_lock(&fd_data
->fd_lock
);
393 if ((kn
->kn_status
& KN_UDATA_SPECIFIC
) == 0)
394 kn
->kn_udata
= kev
->udata
;
395 revents
= necp_fd_poll(fd_data
, POLLIN
, NULL
, current_proc(), 1);
396 lck_mtx_unlock(&fd_data
->fd_lock
);
398 return ((revents
& POLLIN
) != 0);
401 struct filterops necp_fd_rfiltops
= {
403 .f_detach
= necp_fd_knrdetach
,
404 .f_event
= necp_fd_knread
,
405 .f_touch
= necp_fd_knrtouch
,
406 .f_process
= necp_fd_knrprocess
,
410 necpop_kqfilter(struct fileproc
*fp
, struct knote
*kn
, vfs_context_t ctx
)
412 #pragma unused(fp, ctx)
413 struct necp_fd_data
*fd_data
= NULL
;
416 if (kn
->kn_filter
!= EVFILT_READ
) {
417 NECPLOG(LOG_ERR
, "bad filter request %d", kn
->kn_filter
);
418 kn
->kn_flags
= EV_ERROR
;
419 kn
->kn_data
= EINVAL
;
423 fd_data
= (struct necp_fd_data
*)kn
->kn_fp
->f_fglob
->fg_data
;
424 if (fd_data
== NULL
) {
425 NECPLOG0(LOG_ERR
, "No channel for kqfilter");
426 kn
->kn_flags
= EV_ERROR
;
427 kn
->kn_data
= ENOENT
;
431 lck_mtx_lock(&fd_data
->fd_lock
);
432 kn
->kn_filtid
= EVFILTID_NECP_FD
;
433 kn
->kn_hook
= fd_data
;
434 KNOTE_ATTACH(&fd_data
->si
.si_note
, kn
);
436 revents
= necp_fd_poll(fd_data
, POLLIN
, NULL
, current_proc(), 1);
438 lck_mtx_unlock(&fd_data
->fd_lock
);
440 return ((revents
& POLLIN
) != 0);
444 necp_destroy_client_stats(struct necp_client
*client
)
446 if ((client
->stats_area
!= NULL
) &&
447 (client
->stats_handler_context
!= NULL
) &&
448 (client
->stats_uaddr
!= 0)) {
449 // Close old stats if required.
450 int error
= copyin(client
->stats_uaddr
, client
->stats_area
, client
->stats_ulen
);
452 NECPLOG(LOG_ERR
, "necp_destroy_client_stats copyin error on close (%d)", error
);
453 // Not much we can for an error on an obsolete address
455 ntstat_userland_stats_close(client
->stats_handler_context
);
456 FREE(client
->stats_area
, M_NECP
);
457 client
->stats_area
= NULL
;
458 client
->stats_handler_context
= NULL
;
459 client
->stats_uaddr
= 0;
460 client
->stats_ulen
= 0;
465 necp_destroy_client(struct necp_client
*client
)
468 LIST_REMOVE(client
, chain
);
470 // Remove nexus assignment
471 if (client
->assigned_results
!= NULL
) {
472 if (!uuid_is_null(client
->nexus_agent
)) {
473 int netagent_error
= netagent_client_message(client
->nexus_agent
, client
->client_id
,
474 NETAGENT_MESSAGE_TYPE_CLOSE_NEXUS
);
475 if (netagent_error
!= 0) {
476 NECPLOG(LOG_ERR
, "necp_client_remove close nexus error (%d)", netagent_error
);
479 FREE(client
->assigned_results
, M_NETAGENT
);
482 // Remove agent assertions
483 struct necp_client_assertion
*search_assertion
= NULL
;
484 struct necp_client_assertion
*temp_assertion
= NULL
;
485 LIST_FOREACH_SAFE(search_assertion
, &client
->assertion_list
, assertion_chain
, temp_assertion
) {
486 int netagent_error
= netagent_client_message(search_assertion
->asserted_netagent
, client
->client_id
, NETAGENT_MESSAGE_TYPE_CLIENT_UNASSERT
);
487 if (netagent_error
!= 0) {
488 NECPLOG(LOG_ERR
, "necp_client_remove unassert agent error (%d)", netagent_error
);
490 LIST_REMOVE(search_assertion
, assertion_chain
);
491 FREE(search_assertion
, M_NECP
);
493 necp_destroy_client_stats(client
);
495 FREE(client
, M_NECP
);
499 necpop_close(struct fileglob
*fg
, vfs_context_t ctx
)
501 #pragma unused(fg, ctx)
502 struct necp_fd_data
*fd_data
= NULL
;
505 fd_data
= (struct necp_fd_data
*)fg
->fg_data
;
508 if (fd_data
!= NULL
) {
509 lck_rw_lock_exclusive(&necp_fd_lock
);
511 lck_mtx_lock(&fd_data
->fd_lock
);
512 struct necp_client
*client
= NULL
;
513 struct necp_client
*temp_client
= NULL
;
514 LIST_FOREACH_SAFE(client
, &fd_data
->clients
, chain
, temp_client
) {
515 necp_destroy_client(client
);
517 lck_mtx_unlock(&fd_data
->fd_lock
);
519 selthreadclear(&fd_data
->si
);
521 lck_mtx_destroy(&fd_data
->fd_lock
, necp_fd_mtx_grp
);
523 LIST_REMOVE(fd_data
, chain
);
525 lck_rw_done(&necp_fd_lock
);
527 FREE(fd_data
, M_NECP
);
534 /// NECP client utilities
537 necp_find_fd_data(int fd
, struct necp_fd_data
**fd_data
)
539 proc_t p
= current_proc();
540 struct fileproc
*fp
= NULL
;
544 if ((error
= fp_lookup(p
, fd
, &fp
, 1)) != 0) {
547 if (fp
->f_fglob
->fg_ops
->fo_type
!= DTYPE_NETPOLICY
) {
548 fp_drop(p
, fd
, fp
, 1);
552 *fd_data
= (struct necp_fd_data
*)fp
->f_fglob
->fg_data
;
560 necp_netagent_applies_to_client(__unused
struct necp_client
*client
, struct necp_client_parsed_parameters
*parameters
, uuid_t netagent_uuid
)
562 bool applies
= FALSE
;
563 u_int32_t flags
= netagent_get_flags(netagent_uuid
);
564 if (!(flags
& NETAGENT_FLAG_REGISTERED
)) {
565 // Unregistered agents never apply
569 if (flags
& NETAGENT_FLAG_SPECIFIC_USE_ONLY
) {
570 // Specific use agents only apply when required
571 bool required
= FALSE
;
572 if (parameters
!= NULL
) {
573 // Check required agent UUIDs
574 for (int i
= 0; i
< NECP_MAX_PARSED_PARAMETERS
; i
++) {
575 if (uuid_is_null(parameters
->required_netagents
[i
])) {
578 if (uuid_compare(parameters
->required_netagents
[i
], netagent_uuid
) == 0) {
585 // Check required agent types
586 bool fetched_type
= FALSE
;
587 char netagent_domain
[NETAGENT_DOMAINSIZE
];
588 char netagent_type
[NETAGENT_TYPESIZE
];
589 memset(&netagent_domain
, 0, NETAGENT_DOMAINSIZE
);
590 memset(&netagent_type
, 0, NETAGENT_TYPESIZE
);
592 for (int i
= 0; i
< NECP_MAX_PARSED_PARAMETERS
; i
++) {
593 if (strlen(parameters
->required_netagent_types
[i
].netagent_domain
) == 0 ||
594 strlen(parameters
->required_netagent_types
[i
].netagent_type
) == 0) {
599 if (netagent_get_agent_domain_and_type(netagent_uuid
, netagent_domain
, netagent_type
)) {
606 if ((strlen(parameters
->required_netagent_types
[i
].netagent_domain
) == 0 ||
607 strncmp(netagent_domain
, parameters
->required_netagent_types
[i
].netagent_domain
, NETAGENT_DOMAINSIZE
) == 0) &&
608 (strlen(parameters
->required_netagent_types
[i
].netagent_type
) == 0 ||
609 strncmp(netagent_type
, parameters
->required_netagent_types
[i
].netagent_type
, NETAGENT_TYPESIZE
) == 0)) {
623 (flags
& NETAGENT_FLAG_NEXUS_PROVIDER
) &&
624 uuid_is_null(client
->nexus_agent
)) {
625 uuid_copy(client
->nexus_agent
, netagent_uuid
);
632 necp_client_parse_parameters(u_int8_t
*parameters
,
633 u_int32_t parameters_size
,
634 struct necp_client_parsed_parameters
*parsed_parameters
)
639 u_int32_t num_prohibited_interfaces
= 0;
640 u_int32_t num_required_interface_types
= 0;
641 u_int32_t num_prohibited_interface_types
= 0;
642 u_int32_t num_required_agents
= 0;
643 u_int32_t num_prohibited_agents
= 0;
644 u_int32_t num_preferred_agents
= 0;
645 u_int32_t num_required_agent_types
= 0;
646 u_int32_t num_prohibited_agent_types
= 0;
647 u_int32_t num_preferred_agent_types
= 0;
649 if (parsed_parameters
== NULL
) {
653 memset(parsed_parameters
, 0, sizeof(struct necp_client_parsed_parameters
));
655 while ((offset
+ sizeof(u_int8_t
) + sizeof(u_int32_t
)) <= parameters_size
) {
656 u_int8_t type
= necp_buffer_get_tlv_type(parameters
, offset
);
657 u_int32_t length
= necp_buffer_get_tlv_length(parameters
, offset
);
659 if (length
> (parameters_size
- (offset
+ sizeof(u_int8_t
) + sizeof(u_int32_t
)))) {
660 // If the length is larger than what can fit in the remaining parameters size, bail
661 NECPLOG(LOG_ERR
, "Invalid TLV length (%u)", length
);
666 u_int8_t
*value
= necp_buffer_get_tlv_value(parameters
, offset
, NULL
);
669 case NECP_CLIENT_PARAMETER_BOUND_INTERFACE
: {
670 if (length
<= IFXNAMSIZ
&& length
> 0) {
671 ifnet_t bound_interface
= NULL
;
672 char interface_name
[IFXNAMSIZ
];
673 memcpy(interface_name
, value
, length
);
674 interface_name
[length
- 1] = 0; // Make sure the string is NULL terminated
675 if (ifnet_find_by_name(interface_name
, &bound_interface
) == 0) {
676 parsed_parameters
->required_interface_index
= bound_interface
->if_index
;
677 parsed_parameters
->valid_fields
|= NECP_PARSED_PARAMETERS_FIELD_REQUIRED_IF
;
678 ifnet_release(bound_interface
);
683 case NECP_CLIENT_PARAMETER_LOCAL_ADDRESS
: {
684 if (length
>= sizeof(struct necp_policy_condition_addr
)) {
685 struct necp_policy_condition_addr
*address_struct
= (struct necp_policy_condition_addr
*)(void *)value
;
686 if ((address_struct
->address
.sa
.sa_family
== AF_INET
||
687 address_struct
->address
.sa
.sa_family
== AF_INET6
) &&
688 address_struct
->address
.sa
.sa_len
<= length
) {
689 memcpy(&parsed_parameters
->local_addr
, &address_struct
->address
, sizeof(address_struct
->address
));
690 parsed_parameters
->valid_fields
|= NECP_PARSED_PARAMETERS_FIELD_LOCAL_ADDR
;
695 case NECP_CLIENT_PARAMETER_LOCAL_ENDPOINT
: {
696 if (length
>= sizeof(struct necp_client_endpoint
)) {
697 struct necp_client_endpoint
*endpoint
= (struct necp_client_endpoint
*)(void *)value
;
698 if ((endpoint
->u
.endpoint
.endpoint_family
== AF_INET
||
699 endpoint
->u
.endpoint
.endpoint_family
== AF_INET6
) &&
700 endpoint
->u
.endpoint
.endpoint_length
<= length
) {
701 memcpy(&parsed_parameters
->local_addr
, &endpoint
->u
.sa
, sizeof(union necp_sockaddr_union
));
702 parsed_parameters
->valid_fields
|= NECP_PARSED_PARAMETERS_FIELD_LOCAL_ADDR
;
707 case NECP_CLIENT_PARAMETER_REMOTE_ADDRESS
: {
708 if (length
>= sizeof(struct necp_policy_condition_addr
)) {
709 struct necp_policy_condition_addr
*address_struct
= (struct necp_policy_condition_addr
*)(void *)value
;
710 if ((address_struct
->address
.sa
.sa_family
== AF_INET
||
711 address_struct
->address
.sa
.sa_family
== AF_INET6
) &&
712 address_struct
->address
.sa
.sa_len
<= length
) {
713 memcpy(&parsed_parameters
->remote_addr
, &address_struct
->address
, sizeof(address_struct
->address
));
714 parsed_parameters
->valid_fields
|= NECP_PARSED_PARAMETERS_FIELD_REMOTE_ADDR
;
719 case NECP_CLIENT_PARAMETER_REMOTE_ENDPOINT
: {
720 if (length
>= sizeof(struct necp_client_endpoint
)) {
721 struct necp_client_endpoint
*endpoint
= (struct necp_client_endpoint
*)(void *)value
;
722 if ((endpoint
->u
.endpoint
.endpoint_family
== AF_INET
||
723 endpoint
->u
.endpoint
.endpoint_family
== AF_INET6
) &&
724 endpoint
->u
.endpoint
.endpoint_length
<= length
) {
725 memcpy(&parsed_parameters
->remote_addr
, &endpoint
->u
.sa
, sizeof(union necp_sockaddr_union
));
726 parsed_parameters
->valid_fields
|= NECP_PARSED_PARAMETERS_FIELD_REMOTE_ADDR
;
731 case NECP_CLIENT_PARAMETER_PROHIBIT_INTERFACE
: {
732 if (num_prohibited_interfaces
>= NECP_MAX_PARSED_PARAMETERS
) {
735 if (length
<= IFXNAMSIZ
&& length
> 0) {
736 memcpy(parsed_parameters
->prohibited_interfaces
[num_prohibited_interfaces
], value
, length
);
737 parsed_parameters
->prohibited_interfaces
[num_prohibited_interfaces
][length
- 1] = 0; // Make sure the string is NULL terminated
738 num_prohibited_interfaces
++;
739 parsed_parameters
->valid_fields
|= NECP_PARSED_PARAMETERS_FIELD_PROHIBITED_IF
;
743 case NECP_CLIENT_PARAMETER_REQUIRE_IF_TYPE
: {
744 if (num_required_interface_types
>= NECP_MAX_PARSED_PARAMETERS
) {
747 if (length
>= sizeof(u_int8_t
)) {
748 memcpy(&parsed_parameters
->required_interface_types
[num_required_interface_types
], value
, sizeof(u_int8_t
));
749 num_required_interface_types
++;
750 parsed_parameters
->valid_fields
|= NECP_PARSED_PARAMETERS_FIELD_REQUIRED_IFTYPE
;
754 case NECP_CLIENT_PARAMETER_PROHIBIT_IF_TYPE
: {
755 if (num_prohibited_interface_types
>= NECP_MAX_PARSED_PARAMETERS
) {
758 if (length
>= sizeof(u_int8_t
)) {
759 memcpy(&parsed_parameters
->prohibited_interface_types
[num_prohibited_interface_types
], value
, sizeof(u_int8_t
));
760 num_prohibited_interface_types
++;
761 parsed_parameters
->valid_fields
|= NECP_PARSED_PARAMETERS_FIELD_PROHIBITED_IFTYPE
;
765 case NECP_CLIENT_PARAMETER_REQUIRE_AGENT
: {
766 if (num_required_agents
>= NECP_MAX_PARSED_PARAMETERS
) {
769 if (length
>= sizeof(uuid_t
)) {
770 memcpy(&parsed_parameters
->required_netagents
[num_required_agents
], value
, sizeof(uuid_t
));
771 num_required_agents
++;
772 parsed_parameters
->valid_fields
|= NECP_PARSED_PARAMETERS_FIELD_REQUIRED_AGENT
;
776 case NECP_CLIENT_PARAMETER_PROHIBIT_AGENT
: {
777 if (num_prohibited_agents
>= NECP_MAX_PARSED_PARAMETERS
) {
780 if (length
>= sizeof(uuid_t
)) {
781 memcpy(&parsed_parameters
->prohibited_netagents
[num_prohibited_agents
], value
, sizeof(uuid_t
));
782 num_prohibited_agents
++;
783 parsed_parameters
->valid_fields
|= NECP_PARSED_PARAMETERS_FIELD_PROHIBITED_AGENT
;
787 case NECP_CLIENT_PARAMETER_PREFER_AGENT
: {
788 if (num_preferred_agents
>= NECP_MAX_PARSED_PARAMETERS
) {
791 if (length
>= sizeof(uuid_t
)) {
792 memcpy(&parsed_parameters
->preferred_netagents
[num_preferred_agents
], value
, sizeof(uuid_t
));
793 num_preferred_agents
++;
794 parsed_parameters
->valid_fields
|= NECP_PARSED_PARAMETERS_FIELD_PREFERRED_AGENT
;
798 case NECP_CLIENT_PARAMETER_REQUIRE_AGENT_TYPE
: {
799 if (num_required_agent_types
>= NECP_MAX_PARSED_PARAMETERS
) {
802 if (length
>= sizeof(struct necp_client_parameter_netagent_type
)) {
803 memcpy(&parsed_parameters
->required_netagent_types
[num_required_agent_types
], value
, sizeof(struct necp_client_parameter_netagent_type
));
804 num_required_agent_types
++;
805 parsed_parameters
->valid_fields
|= NECP_PARSED_PARAMETERS_FIELD_REQUIRED_AGENT_TYPE
;
809 case NECP_CLIENT_PARAMETER_PROHIBIT_AGENT_TYPE
: {
810 if (num_prohibited_agent_types
>= NECP_MAX_PARSED_PARAMETERS
) {
813 if (length
>= sizeof(struct necp_client_parameter_netagent_type
)) {
814 memcpy(&parsed_parameters
->prohibited_netagent_types
[num_prohibited_agent_types
], value
, sizeof(struct necp_client_parameter_netagent_type
));
815 num_prohibited_agent_types
++;
816 parsed_parameters
->valid_fields
|= NECP_PARSED_PARAMETERS_FIELD_PROHIBITED_AGENT_TYPE
;
820 case NECP_CLIENT_PARAMETER_PREFER_AGENT_TYPE
: {
821 if (num_preferred_agent_types
>= NECP_MAX_PARSED_PARAMETERS
) {
824 if (length
>= sizeof(struct necp_client_parameter_netagent_type
)) {
825 memcpy(&parsed_parameters
->preferred_netagent_types
[num_preferred_agent_types
], value
, sizeof(struct necp_client_parameter_netagent_type
));
826 num_preferred_agent_types
++;
827 parsed_parameters
->valid_fields
|= NECP_PARSED_PARAMETERS_FIELD_PREFERRED_AGENT_TYPE
;
838 offset
+= sizeof(u_int8_t
) + sizeof(u_int32_t
) + length
;
845 necp_assign_client_result(uuid_t netagent_uuid
, uuid_t client_id
,
846 u_int8_t
*assigned_results
, size_t assigned_results_length
)
849 struct necp_fd_data
*client_fd
= NULL
;
850 bool found_client
= FALSE
;
851 bool client_updated
= FALSE
;
853 lck_rw_lock_shared(&necp_fd_lock
);
855 LIST_FOREACH(client_fd
, &necp_fd_list
, chain
) {
856 struct necp_client
*client
= NULL
;
857 lck_mtx_lock(&client_fd
->fd_lock
);
858 LIST_FOREACH(client
, &client_fd
->clients
, chain
) {
859 if (uuid_compare(client
->client_id
, client_id
) == 0) {
860 // Found the right client!
863 if (uuid_compare(client
->nexus_agent
, netagent_uuid
) == 0) {
864 // Verify that the client nexus agent matches
865 if (client
->assigned_results
!= NULL
) {
866 // Release prior result
867 FREE(client
->assigned_results
, M_NETAGENT
);
869 client
->assigned_results
= assigned_results
;
870 client
->assigned_results_length
= assigned_results_length
;
871 client
->assigned_result_read
= FALSE
;
872 client_updated
= TRUE
;
876 if (client_updated
) {
877 necp_fd_notify(client_fd
, true);
879 lck_mtx_unlock(&client_fd
->fd_lock
);
886 lck_rw_done(&necp_fd_lock
);
890 } else if (!client_updated
) {
900 necp_update_client_result(proc_t proc
,
901 struct necp_client
*client
)
903 struct necp_client_result_netagent netagent
;
904 struct necp_aggregate_result result
;
905 struct necp_client_parsed_parameters parsed_parameters
;
908 uuid_clear(client
->nexus_agent
);
910 int error
= necp_client_parse_parameters(client
->parameters
, (u_int32_t
)client
->parameters_length
, &parsed_parameters
);
915 // Check parameters to find best interface
916 u_int matching_if_index
= 0;
917 if (necp_find_matching_interface_index(&parsed_parameters
, &matching_if_index
)) {
918 if (matching_if_index
!= 0) {
919 parsed_parameters
.required_interface_index
= matching_if_index
;
921 // Interface found or not needed, match policy.
922 error
= necp_application_find_policy_match_internal(proc
, client
->parameters
, (u_int32_t
)client
->parameters_length
, &result
, &flags
, matching_if_index
);
927 // Interface not found. Clear out the whole result, make everything fail.
928 memset(&result
, 0, sizeof(result
));
931 // If the original request was scoped, and the policy result matches, make sure the result is scoped
932 if ((result
.routing_result
== NECP_KERNEL_POLICY_RESULT_NONE
||
933 result
.routing_result
== NECP_KERNEL_POLICY_RESULT_PASS
) &&
934 result
.routed_interface_index
!= IFSCOPE_NONE
&&
935 parsed_parameters
.required_interface_index
== result
.routed_interface_index
) {
936 result
.routing_result
= NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED
;
937 result
.routing_result_parameter
.scoped_interface_index
= result
.routed_interface_index
;
940 bool updated
= FALSE
;
941 u_int8_t
*cursor
= client
->result
;
942 const u_int8_t
*max
= client
->result
+ NECP_MAX_CLIENT_RESULT_SIZE
;
943 cursor
= necp_buffer_write_tlv_if_different(cursor
, max
, NECP_CLIENT_RESULT_CLIENT_ID
, sizeof(uuid_t
), client
->client_id
, &updated
);
944 cursor
= necp_buffer_write_tlv_if_different(cursor
, max
, NECP_CLIENT_RESULT_POLICY_RESULT
, sizeof(result
.routing_result
), &result
.routing_result
, &updated
);
945 if (result
.routing_result_parameter
.tunnel_interface_index
!= 0) {
946 cursor
= necp_buffer_write_tlv_if_different(cursor
, max
, NECP_CLIENT_RESULT_POLICY_RESULT_PARAMETER
,
947 sizeof(result
.routing_result_parameter
), &result
.routing_result_parameter
, &updated
);
949 if (result
.filter_control_unit
!= 0) {
950 cursor
= necp_buffer_write_tlv_if_different(cursor
, max
, NECP_CLIENT_RESULT_FILTER_CONTROL_UNIT
,
951 sizeof(result
.filter_control_unit
), &result
.filter_control_unit
, &updated
);
953 if (result
.routed_interface_index
!= 0) {
954 u_int routed_interface_index
= result
.routed_interface_index
;
955 if (result
.routing_result
== NECP_KERNEL_POLICY_RESULT_IP_TUNNEL
&&
956 parsed_parameters
.required_interface_index
!= IFSCOPE_NONE
&&
957 parsed_parameters
.required_interface_index
!= result
.routed_interface_index
) {
958 routed_interface_index
= parsed_parameters
.required_interface_index
;
961 cursor
= necp_buffer_write_tlv_if_different(cursor
, max
, NECP_CLIENT_RESULT_INTERFACE_INDEX
,
962 sizeof(routed_interface_index
), &routed_interface_index
, &updated
);
965 cursor
= necp_buffer_write_tlv_if_different(cursor
, max
, NECP_CLIENT_RESULT_FLAGS
,
966 sizeof(flags
), &flags
, &updated
);
968 for (int i
= 0; i
< NECP_MAX_NETAGENTS
; i
++) {
969 if (uuid_is_null(result
.netagents
[i
])) {
972 uuid_copy(netagent
.netagent_uuid
, result
.netagents
[i
]);
973 netagent
.generation
= netagent_get_generation(netagent
.netagent_uuid
);
974 if (necp_netagent_applies_to_client(client
, &parsed_parameters
, netagent
.netagent_uuid
)) {
975 cursor
= necp_buffer_write_tlv_if_different(cursor
, max
, NECP_CLIENT_RESULT_NETAGENT
, sizeof(netagent
), &netagent
, &updated
);
979 ifnet_head_lock_shared();
980 ifnet_t direct_interface
= NULL
;
981 ifnet_t delegate_interface
= NULL
;
982 ifnet_t original_scoped_interface
= NULL
;
984 if (result
.routed_interface_index
!= IFSCOPE_NONE
&& result
.routed_interface_index
<= (u_int32_t
)if_index
) {
985 direct_interface
= ifindex2ifnet
[result
.routed_interface_index
];
986 } else if (parsed_parameters
.required_interface_index
!= IFSCOPE_NONE
&&
987 parsed_parameters
.required_interface_index
<= (u_int32_t
)if_index
) {
988 // If the request was scoped, but the route didn't match, still grab the agents
989 direct_interface
= ifindex2ifnet
[parsed_parameters
.required_interface_index
];
990 } else if (result
.routed_interface_index
== IFSCOPE_NONE
&&
991 result
.routing_result
== NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED
&&
992 result
.routing_result_parameter
.scoped_interface_index
!= IFSCOPE_NONE
) {
993 direct_interface
= ifindex2ifnet
[result
.routing_result_parameter
.scoped_interface_index
];
995 if (direct_interface
!= NULL
) {
996 delegate_interface
= direct_interface
->if_delegated
.ifp
;
998 if (result
.routing_result
== NECP_KERNEL_POLICY_RESULT_IP_TUNNEL
&&
999 parsed_parameters
.required_interface_index
!= IFSCOPE_NONE
&&
1000 parsed_parameters
.required_interface_index
!= result
.routing_result_parameter
.tunnel_interface_index
&&
1001 parsed_parameters
.required_interface_index
<= (u_int32_t
)if_index
) {
1002 original_scoped_interface
= ifindex2ifnet
[parsed_parameters
.required_interface_index
];
1005 if (original_scoped_interface
!= NULL
) {
1006 struct necp_client_result_interface interface_struct
;
1007 interface_struct
.index
= original_scoped_interface
->if_index
;
1008 interface_struct
.generation
= ifnet_get_generation(original_scoped_interface
);
1009 cursor
= necp_buffer_write_tlv_if_different(cursor
, max
, NECP_CLIENT_RESULT_INTERFACE
, sizeof(interface_struct
), &interface_struct
, &updated
);
1011 if (direct_interface
!= NULL
) {
1012 struct necp_client_result_interface interface_struct
;
1013 interface_struct
.index
= direct_interface
->if_index
;
1014 interface_struct
.generation
= ifnet_get_generation(direct_interface
);
1015 cursor
= necp_buffer_write_tlv_if_different(cursor
, max
, NECP_CLIENT_RESULT_INTERFACE
, sizeof(interface_struct
), &interface_struct
, &updated
);
1017 if (delegate_interface
!= NULL
) {
1018 struct necp_client_result_interface interface_struct
;
1019 interface_struct
.index
= delegate_interface
->if_index
;
1020 interface_struct
.generation
= ifnet_get_generation(delegate_interface
);
1021 cursor
= necp_buffer_write_tlv_if_different(cursor
, max
, NECP_CLIENT_RESULT_INTERFACE
, sizeof(interface_struct
), &interface_struct
, &updated
);
1024 if (original_scoped_interface
!= NULL
) {
1025 ifnet_lock_shared(original_scoped_interface
);
1026 if (original_scoped_interface
->if_agentids
!= NULL
) {
1027 for (u_int32_t i
= 0; i
< original_scoped_interface
->if_agentcount
; i
++) {
1028 if (uuid_is_null(original_scoped_interface
->if_agentids
[i
])) {
1031 uuid_copy(netagent
.netagent_uuid
, original_scoped_interface
->if_agentids
[i
]);
1032 netagent
.generation
= netagent_get_generation(netagent
.netagent_uuid
);
1033 if (necp_netagent_applies_to_client(client
, &parsed_parameters
, netagent
.netagent_uuid
)) {
1034 cursor
= necp_buffer_write_tlv_if_different(cursor
, max
, NECP_CLIENT_RESULT_NETAGENT
, sizeof(netagent
), &netagent
, &updated
);
1038 ifnet_lock_done(original_scoped_interface
);
1040 if (direct_interface
!= NULL
) {
1041 ifnet_lock_shared(direct_interface
);
1042 if (direct_interface
->if_agentids
!= NULL
) {
1043 for (u_int32_t i
= 0; i
< direct_interface
->if_agentcount
; i
++) {
1044 if (uuid_is_null(direct_interface
->if_agentids
[i
])) {
1047 uuid_copy(netagent
.netagent_uuid
, direct_interface
->if_agentids
[i
]);
1048 netagent
.generation
= netagent_get_generation(netagent
.netagent_uuid
);
1049 if (necp_netagent_applies_to_client(client
, &parsed_parameters
, netagent
.netagent_uuid
)) {
1050 cursor
= necp_buffer_write_tlv_if_different(cursor
, max
, NECP_CLIENT_RESULT_NETAGENT
, sizeof(netagent
), &netagent
, &updated
);
1054 ifnet_lock_done(direct_interface
);
1056 if (delegate_interface
!= NULL
) {
1057 ifnet_lock_shared(delegate_interface
);
1058 if (delegate_interface
->if_agentids
!= NULL
) {
1059 for (u_int32_t i
= 0; i
< delegate_interface
->if_agentcount
; i
++) {
1060 if (uuid_is_null(delegate_interface
->if_agentids
[i
])) {
1063 uuid_copy(netagent
.netagent_uuid
, delegate_interface
->if_agentids
[i
]);
1064 netagent
.generation
= netagent_get_generation(netagent
.netagent_uuid
);
1065 if (necp_netagent_applies_to_client(client
, &parsed_parameters
, netagent
.netagent_uuid
)) {
1066 cursor
= necp_buffer_write_tlv_if_different(cursor
, max
, NECP_CLIENT_RESULT_NETAGENT
, sizeof(netagent
), &netagent
, &updated
);
1070 ifnet_lock_done(delegate_interface
);
1074 size_t new_result_length
= (cursor
- client
->result
);
1075 if (new_result_length
!= client
->result_length
) {
1076 client
->result_length
= new_result_length
;
1080 client
->result_read
= FALSE
;
1087 necp_update_all_clients_callout(__unused thread_call_param_t dummy
,
1088 __unused thread_call_param_t arg
)
1091 struct necp_fd_data
*client_fd
= NULL
;
1093 lck_rw_lock_shared(&necp_fd_lock
);
1095 LIST_FOREACH(client_fd
, &necp_fd_list
, chain
) {
1096 bool updated_result
= FALSE
;
1097 struct necp_client
*client
= NULL
;
1098 proc_t proc
= proc_find(client_fd
->proc_pid
);
1103 lck_mtx_lock(&client_fd
->fd_lock
);
1104 LIST_FOREACH(client
, &client_fd
->clients
, chain
) {
1105 if (necp_update_client_result(proc
, client
)) {
1106 updated_result
= TRUE
;
1109 if (updated_result
) {
1110 necp_fd_notify(client_fd
, true);
1112 lck_mtx_unlock(&client_fd
->fd_lock
);
1117 lck_rw_done(&necp_fd_lock
);
1121 necp_update_all_clients(void)
1123 if (necp_client_tcall
== NULL
) {
1124 // Don't try to update clients if the module is not initialized
1128 uint64_t deadline
= 0;
1129 uint64_t leeway
= 0;
1130 clock_interval_to_deadline(necp_timeout_microseconds
, NSEC_PER_USEC
, &deadline
);
1131 clock_interval_to_absolutetime_interval(necp_timeout_leeway_microseconds
, NSEC_PER_USEC
, &leeway
);
1133 thread_call_enter_delayed_with_leeway(necp_client_tcall
, NULL
,
1134 deadline
, leeway
, THREAD_CALL_DELAY_LEEWAY
);
1138 necp_client_remove_agent_from_result(struct necp_client
*client
, uuid_t netagent_uuid
)
1142 u_int8_t
*result_buffer
= client
->result
;
1143 while ((offset
+ sizeof(u_int8_t
) + sizeof(u_int32_t
)) <= client
->result_length
) {
1144 u_int8_t type
= necp_buffer_get_tlv_type(result_buffer
, offset
);
1145 u_int32_t length
= necp_buffer_get_tlv_length(result_buffer
, offset
);
1147 size_t tlv_total_length
= (sizeof(u_int8_t
) + sizeof(u_int32_t
) + length
);
1148 if (type
== NECP_CLIENT_RESULT_NETAGENT
&&
1149 length
== sizeof(struct necp_client_result_netagent
) &&
1150 (offset
+ tlv_total_length
) <= client
->result_length
) {
1151 struct necp_client_result_netagent
*value
= ((struct necp_client_result_netagent
*)(void *)
1152 necp_buffer_get_tlv_value(result_buffer
, offset
, NULL
));
1153 if (uuid_compare(value
->netagent_uuid
, netagent_uuid
) == 0) {
1154 // Found a netagent to remove
1155 // Shift bytes down to remove the tlv, and adjust total length
1156 // Don't adjust the current offset
1157 memmove(result_buffer
+ offset
,
1158 result_buffer
+ offset
+ tlv_total_length
,
1159 client
->result_length
- (offset
+ tlv_total_length
));
1160 client
->result_length
-= tlv_total_length
;
1161 memset(result_buffer
+ client
->result_length
, 0, NECP_MAX_CLIENT_RESULT_SIZE
- client
->result_length
);
1166 offset
+= tlv_total_length
;
1171 necp_force_update_client(uuid_t client_id
, uuid_t remove_netagent_uuid
)
1173 struct necp_fd_data
*client_fd
= NULL
;
1175 lck_rw_lock_shared(&necp_fd_lock
);
1177 LIST_FOREACH(client_fd
, &necp_fd_list
, chain
) {
1178 bool updated_result
= FALSE
;
1179 struct necp_client
*client
= NULL
;
1180 lck_mtx_lock(&client_fd
->fd_lock
);
1181 LIST_FOREACH(client
, &client_fd
->clients
, chain
) {
1182 if (uuid_compare(client
->client_id
, client_id
) == 0) {
1183 if (!uuid_is_null(remove_netagent_uuid
)) {
1184 necp_client_remove_agent_from_result(client
, remove_netagent_uuid
);
1186 client
->assigned_result_read
= FALSE
;
1187 updated_result
= TRUE
;
1188 // Found the client, break
1192 if (updated_result
) {
1193 necp_fd_notify(client_fd
, true);
1195 lck_mtx_unlock(&client_fd
->fd_lock
);
1196 if (updated_result
) {
1197 // Found the client, break
1202 lck_rw_done(&necp_fd_lock
);
1205 /// Interface matching
1207 #define NECP_PARSED_PARAMETERS_INTERESTING_IFNET_FIELDS (NECP_PARSED_PARAMETERS_FIELD_LOCAL_ADDR | \
1208 NECP_PARSED_PARAMETERS_FIELD_PROHIBITED_IF | \
1209 NECP_PARSED_PARAMETERS_FIELD_REQUIRED_IFTYPE | \
1210 NECP_PARSED_PARAMETERS_FIELD_PROHIBITED_IFTYPE | \
1211 NECP_PARSED_PARAMETERS_FIELD_REQUIRED_AGENT | \
1212 NECP_PARSED_PARAMETERS_FIELD_PROHIBITED_AGENT | \
1213 NECP_PARSED_PARAMETERS_FIELD_PREFERRED_AGENT | \
1214 NECP_PARSED_PARAMETERS_FIELD_REQUIRED_AGENT_TYPE | \
1215 NECP_PARSED_PARAMETERS_FIELD_PROHIBITED_AGENT_TYPE | \
1216 NECP_PARSED_PARAMETERS_FIELD_PREFERRED_AGENT_TYPE)
1218 #define NECP_PARSED_PARAMETERS_SCOPED_IFNET_FIELDS (NECP_PARSED_PARAMETERS_FIELD_LOCAL_ADDR | \
1219 NECP_PARSED_PARAMETERS_FIELD_REQUIRED_IFTYPE | \
1220 NECP_PARSED_PARAMETERS_FIELD_REQUIRED_AGENT | \
1221 NECP_PARSED_PARAMETERS_FIELD_PREFERRED_AGENT | \
1222 NECP_PARSED_PARAMETERS_FIELD_REQUIRED_AGENT_TYPE | \
1223 NECP_PARSED_PARAMETERS_FIELD_PREFERRED_AGENT_TYPE)
1225 #define NECP_PARSED_PARAMETERS_PREFERRED_IFNET_FIELDS (NECP_PARSED_PARAMETERS_FIELD_PREFERRED_AGENT | \
1226 NECP_PARSED_PARAMETERS_FIELD_PREFERRED_AGENT_TYPE)
1229 necp_ifnet_matches_type(struct ifnet
*ifp
, u_int8_t interface_type
, bool check_delegates
)
1231 struct ifnet
*check_ifp
= ifp
;
1233 if (if_functional_type(check_ifp
, TRUE
) == interface_type
) {
1236 if (!check_delegates
) {
1239 check_ifp
= check_ifp
->if_delegated
.ifp
;
1246 necp_ifnet_matches_name(struct ifnet
*ifp
, const char *interface_name
, bool check_delegates
)
1248 struct ifnet
*check_ifp
= ifp
;
1250 if (strncmp(check_ifp
->if_xname
, interface_name
, IFXNAMSIZ
) == 0) {
1253 if (!check_delegates
) {
1256 check_ifp
= check_ifp
->if_delegated
.ifp
;
1262 necp_ifnet_matches_agent(struct ifnet
*ifp
, uuid_t
*agent_uuid
, bool check_delegates
)
1264 struct ifnet
*check_ifp
= ifp
;
1266 while (check_ifp
!= NULL
) {
1267 ifnet_lock_shared(check_ifp
);
1268 if (check_ifp
->if_agentids
!= NULL
) {
1269 for (u_int32_t index
= 0; index
< check_ifp
->if_agentcount
; index
++) {
1270 if (uuid_compare(check_ifp
->if_agentids
[index
], *agent_uuid
) == 0) {
1271 ifnet_lock_done(check_ifp
);
1276 ifnet_lock_done(check_ifp
);
1278 if (!check_delegates
) {
1281 check_ifp
= check_ifp
->if_delegated
.ifp
;
1287 necp_necp_ifnet_matches_agent_type(struct ifnet
*ifp
, const char *agent_domain
, const char *agent_type
, bool check_delegates
)
1289 struct ifnet
*check_ifp
= ifp
;
1291 while (check_ifp
!= NULL
) {
1292 ifnet_lock_shared(check_ifp
);
1293 if (check_ifp
->if_agentids
!= NULL
) {
1294 for (u_int32_t index
= 0; index
< check_ifp
->if_agentcount
; index
++) {
1295 if (uuid_is_null(check_ifp
->if_agentids
[index
])) {
1299 char if_agent_domain
[NETAGENT_DOMAINSIZE
] = { 0 };
1300 char if_agent_type
[NETAGENT_TYPESIZE
] = { 0 };
1302 if (netagent_get_agent_domain_and_type(check_ifp
->if_agentids
[index
], if_agent_domain
, if_agent_type
)) {
1303 if ((strlen(agent_domain
) == 0 ||
1304 strncmp(if_agent_domain
, agent_domain
, NETAGENT_DOMAINSIZE
) == 0) &&
1305 (strlen(agent_type
) == 0 ||
1306 strncmp(if_agent_type
, agent_type
, NETAGENT_TYPESIZE
) == 0)) {
1307 ifnet_lock_done(check_ifp
);
1313 ifnet_lock_done(check_ifp
);
1315 if (!check_delegates
) {
1318 check_ifp
= check_ifp
->if_delegated
.ifp
;
1324 necp_ifnet_matches_local_address(struct ifnet
*ifp
, struct sockaddr
*sa
)
1326 struct ifaddr
*ifa
= NULL
;
1327 bool matched_local_address
= FALSE
;
1329 // Transform sa into the ifaddr form
1330 // IPv6 Scope IDs are always embedded in the ifaddr list
1331 struct sockaddr_storage address
;
1332 u_int ifscope
= IFSCOPE_NONE
;
1333 (void)sa_copy(sa
, &address
, &ifscope
);
1334 SIN(&address
)->sin_port
= 0;
1335 if (address
.ss_family
== AF_INET6
) {
1336 SIN6(&address
)->sin6_scope_id
= 0;
1339 ifa
= ifa_ifwithaddr_scoped_locked((struct sockaddr
*)&address
, ifp
->if_index
);
1340 matched_local_address
= (ifa
!= NULL
);
1343 ifaddr_release(ifa
);
1346 return (matched_local_address
);
1350 necp_ifnet_matches_parameters(struct ifnet
*ifp
,
1351 struct necp_client_parsed_parameters
*parsed_parameters
,
1352 u_int32_t
*preferred_count
)
1354 if (preferred_count
) {
1355 *preferred_count
= 0;
1358 if (parsed_parameters
->valid_fields
& NECP_PARSED_PARAMETERS_FIELD_LOCAL_ADDR
) {
1359 if (!necp_ifnet_matches_local_address(ifp
, &parsed_parameters
->local_addr
.sa
)) {
1364 if (parsed_parameters
->valid_fields
& NECP_PARSED_PARAMETERS_FIELD_REQUIRED_IFTYPE
) {
1365 for (int i
= 0; i
< NECP_MAX_PARSED_PARAMETERS
; i
++) {
1366 if (parsed_parameters
->required_interface_types
[i
] == 0) {
1370 if (!necp_ifnet_matches_type(ifp
, parsed_parameters
->required_interface_types
[i
], FALSE
)) {
1376 if (parsed_parameters
->valid_fields
& NECP_PARSED_PARAMETERS_FIELD_PROHIBITED_IFTYPE
) {
1377 for (int i
= 0; i
< NECP_MAX_PARSED_PARAMETERS
; i
++) {
1378 if (parsed_parameters
->prohibited_interface_types
[i
] == 0) {
1382 if (necp_ifnet_matches_type(ifp
, parsed_parameters
->prohibited_interface_types
[i
], TRUE
)) {
1388 if (parsed_parameters
->valid_fields
& NECP_PARSED_PARAMETERS_FIELD_PROHIBITED_IF
) {
1389 for (int i
= 0; i
< NECP_MAX_PARSED_PARAMETERS
; i
++) {
1390 if (strlen(parsed_parameters
->prohibited_interfaces
[i
]) == 0) {
1394 if (necp_ifnet_matches_name(ifp
, parsed_parameters
->prohibited_interfaces
[i
], TRUE
)) {
1400 if (parsed_parameters
->valid_fields
& NECP_PARSED_PARAMETERS_FIELD_REQUIRED_AGENT
) {
1401 for (int i
= 0; i
< NECP_MAX_PARSED_PARAMETERS
; i
++) {
1402 if (uuid_is_null(parsed_parameters
->required_netagents
[i
])) {
1406 if (!necp_ifnet_matches_agent(ifp
, &parsed_parameters
->required_netagents
[i
], FALSE
)) {
1412 if (parsed_parameters
->valid_fields
& NECP_PARSED_PARAMETERS_FIELD_PROHIBITED_AGENT
) {
1413 for (int i
= 0; i
< NECP_MAX_PARSED_PARAMETERS
; i
++) {
1414 if (uuid_is_null(parsed_parameters
->prohibited_netagents
[i
])) {
1418 if (necp_ifnet_matches_agent(ifp
, &parsed_parameters
->prohibited_netagents
[i
], TRUE
)) {
1424 if (parsed_parameters
->valid_fields
& NECP_PARSED_PARAMETERS_FIELD_REQUIRED_AGENT_TYPE
) {
1425 for (int i
= 0; i
< NECP_MAX_PARSED_PARAMETERS
; i
++) {
1426 if (strlen(parsed_parameters
->required_netagent_types
[i
].netagent_domain
) == 0 &&
1427 strlen(parsed_parameters
->required_netagent_types
[i
].netagent_type
) == 0) {
1431 if (!necp_necp_ifnet_matches_agent_type(ifp
, parsed_parameters
->required_netagent_types
[i
].netagent_domain
, parsed_parameters
->required_netagent_types
[i
].netagent_type
, FALSE
)) {
1437 if (parsed_parameters
->valid_fields
& NECP_PARSED_PARAMETERS_FIELD_PROHIBITED_AGENT_TYPE
) {
1438 for (int i
= 0; i
< NECP_MAX_PARSED_PARAMETERS
; i
++) {
1439 if (strlen(parsed_parameters
->prohibited_netagent_types
[i
].netagent_domain
) == 0 &&
1440 strlen(parsed_parameters
->prohibited_netagent_types
[i
].netagent_type
) == 0) {
1444 if (necp_necp_ifnet_matches_agent_type(ifp
, parsed_parameters
->prohibited_netagent_types
[i
].netagent_domain
, parsed_parameters
->prohibited_netagent_types
[i
].netagent_type
, TRUE
)) {
1450 // Checked preferred properties
1451 if (preferred_count
) {
1452 if (parsed_parameters
->valid_fields
& NECP_PARSED_PARAMETERS_FIELD_PREFERRED_AGENT
) {
1453 for (int i
= 0; i
< NECP_MAX_PARSED_PARAMETERS
; i
++) {
1454 if (uuid_is_null(parsed_parameters
->preferred_netagents
[i
])) {
1458 if (necp_ifnet_matches_agent(ifp
, &parsed_parameters
->preferred_netagents
[i
], TRUE
)) {
1459 (*preferred_count
)++;
1464 if (parsed_parameters
->valid_fields
& NECP_PARSED_PARAMETERS_FIELD_PREFERRED_AGENT_TYPE
) {
1465 for (int i
= 0; i
< NECP_MAX_PARSED_PARAMETERS
; i
++) {
1466 if (strlen(parsed_parameters
->preferred_netagent_types
[i
].netagent_domain
) == 0 &&
1467 strlen(parsed_parameters
->preferred_netagent_types
[i
].netagent_type
) == 0) {
1471 if (necp_necp_ifnet_matches_agent_type(ifp
, parsed_parameters
->preferred_netagent_types
[i
].netagent_domain
, parsed_parameters
->preferred_netagent_types
[i
].netagent_type
, TRUE
)) {
1472 (*preferred_count
)++;
1482 necp_find_matching_interface_index(struct necp_client_parsed_parameters
*parsed_parameters
, u_int
*return_ifindex
)
1484 struct ifnet
*ifp
= NULL
;
1485 u_int32_t best_preferred_count
= 0;
1486 bool has_preferred_fields
= FALSE
;
1487 *return_ifindex
= 0;
1489 if (parsed_parameters
->required_interface_index
!= 0) {
1490 *return_ifindex
= parsed_parameters
->required_interface_index
;
1494 if (!(parsed_parameters
->valid_fields
& NECP_PARSED_PARAMETERS_INTERESTING_IFNET_FIELDS
)) {
1498 has_preferred_fields
= (parsed_parameters
->valid_fields
& NECP_PARSED_PARAMETERS_PREFERRED_IFNET_FIELDS
);
1500 // We have interesting parameters to parse and find a matching interface
1501 ifnet_head_lock_shared();
1503 if (!(parsed_parameters
->valid_fields
& NECP_PARSED_PARAMETERS_SCOPED_IFNET_FIELDS
)) {
1504 // We do have fields to match, but they are only prohibitory
1505 // If the first interface in the list matches, we don't need to scope
1506 ifp
= TAILQ_FIRST(&ifnet_ordered_head
);
1507 if (ifp
&& necp_ifnet_matches_parameters(ifp
, parsed_parameters
, NULL
)) {
1508 // Don't set return_ifindex, so the client doesn't need to scope
1514 // First check the ordered interface list
1515 TAILQ_FOREACH(ifp
, &ifnet_ordered_head
, if_ordered_link
) {
1516 u_int32_t preferred_count
= 0;
1517 if (necp_ifnet_matches_parameters(ifp
, parsed_parameters
, &preferred_count
)) {
1518 if (preferred_count
> best_preferred_count
||
1519 *return_ifindex
== 0) {
1521 // Everything matched, and is most preferred. Return this interface.
1522 *return_ifindex
= ifp
->if_index
;
1523 best_preferred_count
= preferred_count
;
1525 if (!has_preferred_fields
) {
1532 // Then check the remaining interfaces
1533 if ((parsed_parameters
->valid_fields
& NECP_PARSED_PARAMETERS_SCOPED_IFNET_FIELDS
) &&
1534 !(parsed_parameters
->valid_fields
& NECP_PARSED_PARAMETERS_FIELD_REQUIRED_IFTYPE
) &&
1535 *return_ifindex
== 0) {
1536 TAILQ_FOREACH(ifp
, &ifnet_head
, if_link
) {
1537 u_int32_t preferred_count
= 0;
1538 if (ifp
->if_ordered_link
.tqe_next
!= NULL
||
1539 ifp
->if_ordered_link
.tqe_prev
!= NULL
) {
1540 // This interface was in the ordered list, skip
1543 if (necp_ifnet_matches_parameters(ifp
, parsed_parameters
, &preferred_count
)) {
1544 if (preferred_count
> best_preferred_count
||
1545 *return_ifindex
== 0) {
1547 // Everything matched, and is most preferred. Return this interface.
1548 *return_ifindex
= ifp
->if_index
;
1549 best_preferred_count
= preferred_count
;
1551 if (!has_preferred_fields
) {
1561 if ((parsed_parameters
->valid_fields
== (parsed_parameters
->valid_fields
& NECP_PARSED_PARAMETERS_PREFERRED_IFNET_FIELDS
)) &&
1562 best_preferred_count
== 0) {
1563 // If only has preferred fields, and nothing was found, clear the interface index and return TRUE
1564 *return_ifindex
= 0;
1568 return (*return_ifindex
!= 0);
1572 necp_find_netstat_data(struct necp_client
*client
, union necp_sockaddr_union
*local
, union necp_sockaddr_union
*remote
, u_int32_t
*ifindex
, uuid_t euuid
, u_int32_t
*traffic_class
)
1575 u_int8_t
*parameters
;
1576 u_int32_t parameters_size
;
1578 parameters
= client
->parameters
;
1579 parameters_size
= (u_int32_t
)client
->parameters_length
;
1581 while ((offset
+ sizeof(u_int8_t
) + sizeof(u_int32_t
)) <= parameters_size
) {
1582 u_int8_t type
= necp_buffer_get_tlv_type(parameters
, offset
);
1583 u_int32_t length
= necp_buffer_get_tlv_length(parameters
, offset
);
1585 if (length
> (parameters_size
- (offset
+ sizeof(u_int8_t
) + sizeof(u_int32_t
)))) {
1586 // If the length is larger than what can fit in the remaining parameters size, bail
1587 NECPLOG(LOG_ERR
, "Invalid TLV length (%u)", length
);
1592 u_int8_t
*value
= necp_buffer_get_tlv_value(parameters
, offset
, NULL
);
1593 if (value
!= NULL
) {
1595 case NECP_CLIENT_PARAMETER_REAL_APPLICATION
: {
1596 if (length
>= sizeof(uuid_t
)) {
1597 uuid_copy(euuid
, value
);
1601 case NECP_CLIENT_PARAMETER_TRAFFIC_CLASS
: {
1602 if (length
>= sizeof(u_int32_t
)) {
1603 memcpy(traffic_class
, value
, sizeof(u_int32_t
));
1607 case NECP_CLIENT_PARAMETER_BOUND_INTERFACE
: {
1608 if (length
<= IFXNAMSIZ
&& length
> 0) {
1609 ifnet_t bound_interface
= NULL
;
1610 char interface_name
[IFXNAMSIZ
];
1611 memcpy(interface_name
, value
, length
);
1612 interface_name
[length
- 1] = 0; // Make sure the string is NULL terminated
1613 if (ifnet_find_by_name(interface_name
, &bound_interface
) == 0) {
1614 *ifindex
= bound_interface
->if_index
;
1615 ifnet_release(bound_interface
);
1620 case NECP_CLIENT_PARAMETER_LOCAL_ADDRESS
: {
1621 if (length
>= sizeof(struct necp_policy_condition_addr
)) {
1622 struct necp_policy_condition_addr
*address_struct
= (struct necp_policy_condition_addr
*)(void *)value
;
1623 memcpy(local
, &address_struct
->address
, sizeof(address_struct
->address
));
1627 case NECP_CLIENT_PARAMETER_REMOTE_ADDRESS
: {
1628 if (length
>= sizeof(struct necp_policy_condition_addr
)) {
1629 struct necp_policy_condition_addr
*address_struct
= (struct necp_policy_condition_addr
*)(void *)value
;
1630 memcpy(remote
, &address_struct
->address
, sizeof(address_struct
->address
));
1640 offset
+= sizeof(u_int8_t
) + sizeof(u_int32_t
) + length
;
1645 necp_fillout_current_process_details(u_int32_t
*pid
, u_int64_t
*upid
, unsigned char *uuid
, char *pname
, size_t len
)
1647 *pid
= proc_selfpid();
1648 *upid
= proc_uniqueid(current_proc());
1649 proc_selfname(pname
, (int) len
);
1650 proc_getexecutableuuid(current_proc(), uuid
, sizeof(uuid_t
));
1653 // Called from NetworkStatistics when it wishes to collect latest information for a TCP flow.
1654 // It is a responsibility of NetworkStatistics to have previously zeroed any supplied memory.
1656 necp_request_tcp_netstats(userland_stats_provider_context
*ctx
,
1657 nstat_counts
*countsp
,
1664 struct necp_client
*client
= (struct necp_client
*)ctx
;
1665 struct necp_tcp_stats
*tcpstats
= (struct necp_tcp_stats
*)client
->stats_area
;
1666 if (tcpstats
== NULL
) {
1671 *countsp
= *((struct nstat_counts
*)&tcpstats
->necp_tcp_counts
);
1675 nstat_tcp_descriptor
*desc
= (nstat_tcp_descriptor
*)metadatap
;
1677 // Metadata for the process
1678 necp_fillout_current_process_details(&desc
->pid
, &desc
->upid
, desc
->uuid
, desc
->pname
, sizeof(desc
->pname
));
1680 // Metadata that the necp client should have in TLV format.
1681 necp_find_netstat_data(client
, (union necp_sockaddr_union
*)&desc
->local
, (union necp_sockaddr_union
*)&desc
->remote
, &desc
->ifindex
, desc
->euuid
, &desc
->traffic_class
);
1684 desc
->rcvbufsize
= tcpstats
->necp_tcp_basic
.rcvbufsize
;
1685 desc
->rcvbufused
= tcpstats
->necp_tcp_basic
.rcvbufused
;
1686 desc
->eupid
= tcpstats
->necp_tcp_basic
.eupid
;
1687 desc
->epid
= tcpstats
->necp_tcp_basic
.epid
;
1688 memcpy(desc
->vuuid
, tcpstats
->necp_tcp_basic
.vuuid
, sizeof(desc
->vuuid
));
1689 desc
->ifnet_properties
= tcpstats
->necp_tcp_basic
.ifnet_properties
;
1691 // Additional TCP specific data
1692 desc
->sndbufsize
= tcpstats
->necp_tcp_extra
.sndbufsize
;
1693 desc
->sndbufused
= tcpstats
->necp_tcp_extra
.sndbufused
;
1694 desc
->txunacked
= tcpstats
->necp_tcp_extra
.txunacked
;
1695 desc
->txwindow
= tcpstats
->necp_tcp_extra
.txwindow
;
1696 desc
->txcwindow
= tcpstats
->necp_tcp_extra
.txcwindow
;
1697 desc
->traffic_mgt_flags
= tcpstats
->necp_tcp_extra
.traffic_mgt_flags
;
1699 if (tcpstats
->necp_tcp_extra
.cc_alg_index
< TCP_CC_ALGO_COUNT
) {
1700 strlcpy(desc
->cc_algo
, tcp_cc_algo_list
[tcpstats
->necp_tcp_extra
.cc_alg_index
]->name
, sizeof(desc
->cc_algo
));
1702 strlcpy(desc
->cc_algo
, "unknown", sizeof(desc
->cc_algo
));
1705 desc
->connstatus
.write_probe_failed
= tcpstats
->necp_tcp_extra
.probestatus
.write_probe_failed
;
1706 desc
->connstatus
.read_probe_failed
= tcpstats
->necp_tcp_extra
.probestatus
.read_probe_failed
;
1707 desc
->connstatus
.conn_probe_failed
= tcpstats
->necp_tcp_extra
.probestatus
.conn_probe_failed
;
1712 // Called from NetworkStatistics when it wishes to collect latest information for a UDP flow.
1714 necp_request_udp_netstats(userland_stats_provider_context
*ctx
,
1715 nstat_counts
*countsp
,
1722 struct necp_client
*client
= (struct necp_client
*)ctx
;
1723 struct necp_udp_stats
*udpstats
= (struct necp_udp_stats
*)client
->stats_area
;
1724 if (udpstats
== NULL
) {
1729 *countsp
= *((struct nstat_counts
*)&udpstats
->necp_udp_counts
);
1733 nstat_udp_descriptor
*desc
= (nstat_udp_descriptor
*)metadatap
;
1735 // Metadata for the process
1736 necp_fillout_current_process_details(&desc
->pid
, &desc
->upid
, desc
->uuid
, desc
->pname
, sizeof(desc
->pname
));
1738 // Metadata that the necp client should have in TLV format.
1739 necp_find_netstat_data(client
, (union necp_sockaddr_union
*)&desc
->local
, (union necp_sockaddr_union
*)&desc
->remote
, &desc
->ifindex
, desc
->euuid
, &desc
->traffic_class
);
1741 // Basic metadata is all that is required for UDP
1742 desc
->rcvbufsize
= udpstats
->necp_udp_basic
.rcvbufsize
;
1743 desc
->rcvbufused
= udpstats
->necp_udp_basic
.rcvbufused
;
1744 desc
->eupid
= udpstats
->necp_udp_basic
.eupid
;
1745 desc
->epid
= udpstats
->necp_udp_basic
.epid
;
1746 memcpy(desc
->vuuid
, udpstats
->necp_udp_basic
.vuuid
, sizeof(desc
->euuid
));
1747 desc
->ifnet_properties
= udpstats
->necp_udp_basic
.ifnet_properties
;
1753 necp_skywalk_priv_check_cred(proc_t p
, kauth_cred_t cred
)
1755 #pragma unused(p, cred)
1762 necp_open(struct proc
*p
, struct necp_open_args
*uap
, int *retval
)
1764 #pragma unused(retval)
1766 struct necp_fd_data
*fd_data
= NULL
;
1767 struct fileproc
*fp
= NULL
;
1770 if (uap
->flags
& NECP_OPEN_FLAG_OBSERVER
) {
1771 if (necp_skywalk_priv_check_cred(p
, kauth_cred_get()) != 0 &&
1772 priv_check_cred(kauth_cred_get(), PRIV_NET_PRIVILEGED_NETWORK_STATISTICS
, 0) != 0) {
1773 NECPLOG0(LOG_ERR
, "Client does not hold necessary entitlement to observe other NECP clients");
1779 error
= falloc(p
, &fp
, &fd
, vfs_context_current());
1784 if ((fd_data
= _MALLOC(sizeof(struct necp_fd_data
), M_NECP
,
1785 M_WAITOK
| M_ZERO
)) == NULL
) {
1790 fd_data
->flags
= uap
->flags
;
1791 LIST_INIT(&fd_data
->clients
);
1792 lck_mtx_init(&fd_data
->fd_lock
, necp_fd_mtx_grp
, necp_fd_mtx_attr
);
1793 klist_init(&fd_data
->si
.si_note
);
1794 fd_data
->proc_pid
= proc_pid(p
);
1796 fp
->f_fglob
->fg_flag
= FREAD
;
1797 fp
->f_fglob
->fg_ops
= &necp_fd_ops
;
1798 fp
->f_fglob
->fg_data
= fd_data
;
1802 *fdflags(p
, fd
) |= (UF_EXCLOSE
| UF_FORKCLOSE
);
1803 procfdtbl_releasefd(p
, fd
, NULL
);
1804 fp_drop(p
, fd
, fp
, 1);
1808 lck_rw_lock_exclusive(&necp_fd_lock
);
1809 LIST_INSERT_HEAD(&necp_fd_list
, fd_data
, chain
);
1810 lck_rw_done(&necp_fd_lock
);
1820 if (fd_data
!= NULL
) {
1821 FREE(fd_data
, M_NECP
);
1830 necp_client_add(struct necp_fd_data
*fd_data
, struct necp_client_action_args
*uap
, int *retval
)
1833 struct necp_client
*client
= NULL
;
1835 if (uap
->client_id
== 0 || uap
->client_id_len
!= sizeof(uuid_t
) ||
1836 uap
->buffer_size
== 0 || uap
->buffer_size
> NECP_MAX_CLIENT_PARAMETERS_SIZE
|| uap
->buffer
== 0) {
1841 if ((client
= _MALLOC(sizeof(struct necp_client
) + uap
->buffer_size
, M_NECP
,
1842 M_WAITOK
| M_ZERO
)) == NULL
) {
1847 error
= copyin(uap
->buffer
, client
->parameters
, uap
->buffer_size
);
1849 NECPLOG(LOG_ERR
, "necp_client_add parameters copyin error (%d)", error
);
1853 client
->parameters_length
= uap
->buffer_size
;
1855 uuid_generate_random(client
->client_id
);
1856 LIST_INIT(&client
->assertion_list
);
1858 error
= copyout(client
->client_id
, uap
->client_id
, sizeof(uuid_t
));
1860 NECPLOG(LOG_ERR
, "necp_client_add client_id copyout error (%d)", error
);
1864 lck_mtx_lock(&fd_data
->fd_lock
);
1865 LIST_INSERT_HEAD(&fd_data
->clients
, client
, chain
);
1867 // Prime the client result
1868 (void)necp_update_client_result(current_proc(), client
);
1869 lck_mtx_unlock(&fd_data
->fd_lock
);
1872 if (client
!= NULL
) {
1873 FREE(client
, M_NECP
);
1883 necp_client_remove(struct necp_fd_data
*fd_data
, struct necp_client_action_args
*uap
, int *retval
)
1886 struct necp_client
*client
= NULL
;
1887 struct necp_client
*temp_client
= NULL
;
1890 if (uap
->client_id
== 0 || uap
->client_id_len
!= sizeof(uuid_t
)) {
1895 error
= copyin(uap
->client_id
, client_id
, sizeof(uuid_t
));
1897 NECPLOG(LOG_ERR
, "necp_client_remove copyin client_id error (%d)", error
);
1901 lck_mtx_lock(&fd_data
->fd_lock
);
1902 LIST_FOREACH_SAFE(client
, &fd_data
->clients
, chain
, temp_client
) {
1903 if (uuid_compare(client
->client_id
, client_id
) == 0) {
1904 necp_destroy_client(client
);
1907 lck_mtx_unlock(&fd_data
->fd_lock
);
1915 necp_client_copy_internal(struct necp_client
*client
, bool client_is_observed
, struct necp_client_action_args
*uap
, int *retval
)
1919 if (uap
->action
== NECP_CLIENT_ACTION_COPY_PARAMETERS
) {
1920 if (uap
->buffer_size
< client
->parameters_length
) {
1924 error
= copyout(client
->parameters
, uap
->buffer
, client
->parameters_length
);
1926 NECPLOG(LOG_ERR
, "necp_client_copy parameters copyout error (%d)", error
);
1929 *retval
= client
->parameters_length
;
1930 } else if (uap
->action
== NECP_CLIENT_ACTION_COPY_RESULT
) {
1931 if (uap
->buffer_size
< (client
->result_length
+ client
->assigned_results_length
)) {
1935 error
= copyout(client
->result
, uap
->buffer
, client
->result_length
);
1937 NECPLOG(LOG_ERR
, "necp_client_copy result copyout error (%d)", error
);
1940 if (client
->assigned_results_length
&& client
->assigned_results
) {
1941 error
= copyout(client
->assigned_results
, uap
->buffer
+ client
->result_length
, client
->assigned_results_length
);
1943 NECPLOG(LOG_ERR
, "necp_client_copy assigned results copyout error (%d)", error
);
1946 *retval
= client
->result_length
+ client
->assigned_results_length
;
1948 *retval
= client
->result_length
;
1951 if (!client_is_observed
) {
1952 client
->result_read
= TRUE
;
1953 client
->assigned_result_read
= TRUE
;
1962 necp_client_copy(struct necp_fd_data
*fd_data
, struct necp_client_action_args
*uap
, int *retval
)
1965 struct necp_client
*find_client
= NULL
;
1966 struct necp_client
*client
= NULL
;
1968 uuid_clear(client_id
);
1972 if (uap
->buffer_size
== 0 || uap
->buffer
== 0) {
1977 if (uap
->action
!= NECP_CLIENT_ACTION_COPY_PARAMETERS
&&
1978 uap
->action
!= NECP_CLIENT_ACTION_COPY_RESULT
) {
1983 if (uap
->client_id
) {
1984 if (uap
->client_id_len
!= sizeof(uuid_t
)) {
1985 NECPLOG(LOG_ERR
, "Incorrect length (got %d, expected %d)", uap
->client_id_len
, sizeof(uuid_t
));
1990 error
= copyin(uap
->client_id
, client_id
, sizeof(uuid_t
));
1992 NECPLOG(LOG_ERR
, "necp_client_copy client_id copyin error (%d)", error
);
1997 lck_mtx_lock(&fd_data
->fd_lock
);
1998 LIST_FOREACH(find_client
, &fd_data
->clients
, chain
) {
1999 if (uap
->action
== NECP_CLIENT_ACTION_COPY_RESULT
&&
2000 uuid_is_null(client_id
)) {
2001 if (!find_client
->result_read
|| !find_client
->assigned_result_read
) {
2002 client
= find_client
;
2005 } else if (uuid_compare(find_client
->client_id
, client_id
) == 0) {
2006 client
= find_client
;
2011 if (client
!= NULL
) {
2012 error
= necp_client_copy_internal(client
, FALSE
, uap
, retval
);
2015 // Unlock our own client before moving on or returning
2016 lck_mtx_unlock(&fd_data
->fd_lock
);
2018 if (client
== NULL
) {
2019 if (fd_data
->flags
& NECP_OPEN_FLAG_OBSERVER
) {
2020 // Observers are allowed to lookup clients on other fds
2023 lck_rw_lock_shared(&necp_fd_lock
);
2024 struct necp_fd_data
*client_fd
= NULL
;
2025 LIST_FOREACH(client_fd
, &necp_fd_list
, chain
) {
2027 lck_mtx_lock(&client_fd
->fd_lock
);
2029 LIST_FOREACH(find_client
, &client_fd
->clients
, chain
) {
2030 if (uuid_compare(find_client
->client_id
, client_id
) == 0) {
2031 client
= find_client
;
2036 if (client
!= NULL
) {
2037 // Matched, copy out data
2038 error
= necp_client_copy_internal(client
, TRUE
, uap
, retval
);
2042 lck_mtx_unlock(&client_fd
->fd_lock
);
2044 if (client
!= NULL
) {
2050 lck_rw_done(&necp_fd_lock
);
2052 // No client found, fail
2053 if (client
== NULL
) {
2058 // No client found, and not allowed to search other fds, fail
2069 necp_client_list(struct necp_fd_data
*fd_data
, struct necp_client_action_args
*uap
, int *retval
)
2072 struct necp_client
*find_client
= NULL
;
2073 uuid_t
*list
= NULL
;
2074 u_int32_t requested_client_count
= 0;
2075 u_int32_t client_count
= 0;
2077 if (uap
->buffer_size
< sizeof(requested_client_count
) || uap
->buffer
== 0) {
2082 if (!(fd_data
->flags
& NECP_OPEN_FLAG_OBSERVER
)) {
2083 NECPLOG0(LOG_ERR
, "Client does not hold necessary entitlement to list other NECP clients");
2088 error
= copyin(uap
->buffer
, &requested_client_count
, sizeof(requested_client_count
));
2093 if (uap
->buffer_size
!= (sizeof(requested_client_count
) + requested_client_count
* sizeof(uuid_t
))) {
2098 if (requested_client_count
> 0) {
2099 if ((list
= _MALLOC(requested_client_count
* sizeof(uuid_t
), M_NECP
, M_WAITOK
| M_ZERO
)) == NULL
) {
2106 lck_rw_lock_shared(&necp_fd_lock
);
2107 struct necp_fd_data
*client_fd
= NULL
;
2108 LIST_FOREACH(client_fd
, &necp_fd_list
, chain
) {
2110 lck_mtx_lock(&client_fd
->fd_lock
);
2112 LIST_FOREACH(find_client
, &client_fd
->clients
, chain
) {
2113 if (!uuid_is_null(find_client
->client_id
)) {
2114 if (client_count
< requested_client_count
) {
2115 uuid_copy(list
[client_count
], find_client
->client_id
);
2120 lck_mtx_unlock(&client_fd
->fd_lock
);
2124 lck_rw_done(&necp_fd_lock
);
2126 error
= copyout(&client_count
, uap
->buffer
, sizeof(client_count
));
2128 NECPLOG(LOG_ERR
, "necp_client_list buffer copyout error (%d)", error
);
2132 if (requested_client_count
> 0 &&
2135 error
= copyout(list
, uap
->buffer
+ sizeof(client_count
), requested_client_count
* sizeof(uuid_t
));
2137 NECPLOG(LOG_ERR
, "necp_client_list client count copyout error (%d)", error
);
2151 necp_client_request_nexus(struct necp_fd_data
*fd_data
, struct necp_client_action_args
*uap
, int *retval
)
2154 struct necp_client
*client
= NULL
;
2156 bool requested_nexus
= FALSE
;
2158 if (uap
->client_id
== 0 || uap
->client_id_len
!= sizeof(uuid_t
)) {
2163 error
= copyin(uap
->client_id
, client_id
, sizeof(uuid_t
));
2165 NECPLOG(LOG_ERR
, "necp_client_request_nexus copyin client_id error (%d)", error
);
2169 lck_mtx_lock(&fd_data
->fd_lock
);
2170 LIST_FOREACH(client
, &fd_data
->clients
, chain
) {
2171 if (uuid_compare(client
->client_id
, client_id
) == 0) {
2172 // Request from nexus agent
2173 if (!uuid_is_null(client
->nexus_agent
)) {
2174 error
= netagent_client_message(client
->nexus_agent
, client
->client_id
,
2175 NETAGENT_MESSAGE_TYPE_REQUEST_NEXUS
);
2177 requested_nexus
= TRUE
;
2183 lck_mtx_unlock(&fd_data
->fd_lock
);
2185 if (!requested_nexus
&&
2196 necp_client_add_assertion(struct necp_client
*client
, uuid_t netagent_uuid
)
2198 struct necp_client_assertion
*new_assertion
= NULL
;
2200 MALLOC(new_assertion
, struct necp_client_assertion
*, sizeof(*new_assertion
), M_NECP
, M_WAITOK
);
2201 if (new_assertion
== NULL
) {
2202 NECPLOG0(LOG_ERR
, "Failed to allocate assertion");
2206 uuid_copy(new_assertion
->asserted_netagent
, netagent_uuid
);
2208 LIST_INSERT_HEAD(&client
->assertion_list
, new_assertion
, assertion_chain
);
2212 necp_client_remove_assertion(struct necp_client
*client
, uuid_t netagent_uuid
)
2214 struct necp_client_assertion
*found_assertion
= NULL
;
2215 struct necp_client_assertion
*search_assertion
= NULL
;
2216 LIST_FOREACH(search_assertion
, &client
->assertion_list
, assertion_chain
) {
2217 if (uuid_compare(search_assertion
->asserted_netagent
, netagent_uuid
) == 0) {
2218 found_assertion
= search_assertion
;
2223 if (found_assertion
== NULL
) {
2224 NECPLOG0(LOG_ERR
, "Netagent uuid not previously asserted");
2228 LIST_REMOVE(found_assertion
, assertion_chain
);
2229 FREE(found_assertion
, M_NECP
);
2234 necp_client_agent_action(struct necp_fd_data
*fd_data
, struct necp_client_action_args
*uap
, int *retval
)
2237 struct necp_client
*matched_client
= NULL
;
2238 struct necp_client
*client
= NULL
;
2240 bool acted_on_agent
= FALSE
;
2241 u_int8_t
*parameters
= NULL
;
2242 size_t parameters_size
= uap
->buffer_size
;
2244 if (uap
->client_id
== 0 || uap
->client_id_len
!= sizeof(uuid_t
) ||
2245 uap
->buffer_size
== 0 || uap
->buffer
== 0) {
2250 error
= copyin(uap
->client_id
, client_id
, sizeof(uuid_t
));
2252 NECPLOG(LOG_ERR
, "necp_client_agent_action copyin client_id error (%d)", error
);
2256 if ((parameters
= _MALLOC(uap
->buffer_size
, M_NECP
, M_WAITOK
| M_ZERO
)) == NULL
) {
2261 error
= copyin(uap
->buffer
, parameters
, uap
->buffer_size
);
2263 NECPLOG(LOG_ERR
, "necp_client_agent_action parameters copyin error (%d)", error
);
2267 lck_mtx_lock(&fd_data
->fd_lock
);
2268 LIST_FOREACH(client
, &fd_data
->clients
, chain
) {
2269 if (uuid_compare(client
->client_id
, client_id
) == 0) {
2270 matched_client
= client
;
2274 if (matched_client
) {
2276 while ((offset
+ sizeof(u_int8_t
) + sizeof(u_int32_t
)) <= parameters_size
) {
2277 u_int8_t type
= necp_buffer_get_tlv_type(parameters
, offset
);
2278 u_int32_t length
= necp_buffer_get_tlv_length(parameters
, offset
);
2280 if (length
> (parameters_size
- (offset
+ sizeof(u_int8_t
) + sizeof(u_int32_t
)))) {
2281 // If the length is larger than what can fit in the remaining parameters size, bail
2282 NECPLOG(LOG_ERR
, "Invalid TLV length (%u)", length
);
2287 u_int8_t
*value
= necp_buffer_get_tlv_value(parameters
, offset
, NULL
);
2288 if (length
>= sizeof(uuid_t
) &&
2290 (type
== NECP_CLIENT_PARAMETER_TRIGGER_AGENT
||
2291 type
== NECP_CLIENT_PARAMETER_ASSERT_AGENT
||
2292 type
== NECP_CLIENT_PARAMETER_UNASSERT_AGENT
)) {
2295 uuid_copy(agent_uuid
, value
);
2296 u_int8_t netagent_message_type
= 0;
2297 if (type
== NECP_CLIENT_PARAMETER_TRIGGER_AGENT
) {
2298 netagent_message_type
= NETAGENT_MESSAGE_TYPE_CLIENT_TRIGGER
;
2299 } else if (type
== NECP_CLIENT_PARAMETER_ASSERT_AGENT
) {
2300 netagent_message_type
= NETAGENT_MESSAGE_TYPE_CLIENT_ASSERT
;
2301 } else if (type
== NECP_CLIENT_PARAMETER_UNASSERT_AGENT
) {
2302 netagent_message_type
= NETAGENT_MESSAGE_TYPE_CLIENT_UNASSERT
;
2305 // Before unasserting, verify that the assertion was already taken
2306 if (type
== NECP_CLIENT_PARAMETER_UNASSERT_AGENT
) {
2307 if (!necp_client_remove_assertion(client
, agent_uuid
)) {
2313 error
= netagent_client_message(agent_uuid
, client_id
,
2314 netagent_message_type
);
2316 acted_on_agent
= TRUE
;
2321 // Only save the assertion if the action succeeded
2322 if (type
== NECP_CLIENT_PARAMETER_ASSERT_AGENT
) {
2323 necp_client_add_assertion(client
, agent_uuid
);
2328 offset
+= sizeof(u_int8_t
) + sizeof(u_int32_t
) + length
;
2331 lck_mtx_unlock(&fd_data
->fd_lock
);
2333 if (!acted_on_agent
&&
2339 if (parameters
!= NULL
) {
2340 FREE(parameters
, M_NECP
);
2348 necp_client_copy_agent(__unused
struct necp_fd_data
*fd_data
, struct necp_client_action_args
*uap
, int *retval
)
2353 if (uap
->client_id
== 0 || uap
->client_id_len
!= sizeof(uuid_t
) ||
2354 uap
->buffer_size
== 0 || uap
->buffer
== 0) {
2355 NECPLOG0(LOG_ERR
, "necp_client_copy_agent bad input");
2360 error
= copyin(uap
->client_id
, agent_uuid
, sizeof(uuid_t
));
2362 NECPLOG(LOG_ERR
, "necp_client_copy_agent copyin agent_uuid error (%d)", error
);
2366 error
= netagent_copyout(agent_uuid
, uap
->buffer
, uap
->buffer_size
);
2368 NECPLOG(LOG_ERR
, "necp_client_copy_agent netagent_copyout error (%d)", error
);
2378 necp_client_agent_use(struct necp_fd_data
*fd_data
, struct necp_client_action_args
*uap
, int *retval
)
2381 struct necp_client
*matched_client
= NULL
;
2382 struct necp_client
*client
= NULL
;
2384 struct necp_agent_use_parameters parameters
;
2386 if (uap
->client_id
== 0 || uap
->client_id_len
!= sizeof(uuid_t
) ||
2387 uap
->buffer_size
!= sizeof(parameters
) || uap
->buffer
== 0) {
2392 error
= copyin(uap
->client_id
, client_id
, sizeof(uuid_t
));
2394 NECPLOG(LOG_ERR
, "Copyin client_id error (%d)", error
);
2398 error
= copyin(uap
->buffer
, ¶meters
, uap
->buffer_size
);
2400 NECPLOG(LOG_ERR
, "Parameters copyin error (%d)", error
);
2404 lck_mtx_lock(&fd_data
->fd_lock
);
2405 LIST_FOREACH(client
, &fd_data
->clients
, chain
) {
2406 if (uuid_compare(client
->client_id
, client_id
) == 0) {
2407 matched_client
= client
;
2412 if (matched_client
) {
2413 error
= netagent_use(parameters
.agent_uuid
, ¶meters
.out_use_count
);
2418 lck_mtx_unlock(&fd_data
->fd_lock
);
2421 error
= copyout(¶meters
, uap
->buffer
, uap
->buffer_size
);
2423 NECPLOG(LOG_ERR
, "Parameters copyout error (%d)", error
);
2435 necp_client_copy_interface(__unused
struct necp_fd_data
*fd_data
, struct necp_client_action_args
*uap
, int *retval
)
2438 u_int32_t interface_index
= 0;
2439 struct necp_interface_details interface_details
;
2441 if (uap
->client_id
== 0 || uap
->client_id_len
!= sizeof(u_int32_t
) ||
2442 uap
->buffer_size
< sizeof(interface_details
) || uap
->buffer
== 0) {
2443 NECPLOG0(LOG_ERR
, "necp_client_copy_interface bad input");
2448 error
= copyin(uap
->client_id
, &interface_index
, sizeof(u_int32_t
));
2450 NECPLOG(LOG_ERR
, "necp_client_copy_interface copyin interface_index error (%d)", error
);
2454 if (interface_index
== 0) {
2456 NECPLOG(LOG_ERR
, "necp_client_copy_interface bad interface_index (%d)", interface_index
);
2460 memset(&interface_details
, 0, sizeof(interface_details
));
2462 ifnet_head_lock_shared();
2463 ifnet_t interface
= NULL
;
2464 if (interface_index
!= IFSCOPE_NONE
&& interface_index
<= (u_int32_t
)if_index
) {
2465 interface
= ifindex2ifnet
[interface_index
];
2468 if (interface
!= NULL
) {
2469 if (interface
->if_xname
!= NULL
) {
2470 strlcpy((char *)&interface_details
.name
, interface
->if_xname
, sizeof(interface_details
.name
));
2472 interface_details
.index
= interface
->if_index
;
2473 interface_details
.generation
= ifnet_get_generation(interface
);
2474 if (interface
->if_delegated
.ifp
!= NULL
) {
2475 interface_details
.delegate_index
= interface
->if_delegated
.ifp
->if_index
;
2477 interface_details
.functional_type
= if_functional_type(interface
, TRUE
);
2478 if (IFNET_IS_EXPENSIVE(interface
)) {
2479 interface_details
.flags
|= NECP_INTERFACE_FLAG_EXPENSIVE
;
2481 interface_details
.mtu
= interface
->if_mtu
;
2483 u_int8_t ipv4_signature_len
= sizeof(interface_details
.ipv4_signature
);
2484 u_int16_t ipv4_signature_flags
;
2485 ifnet_get_netsignature(interface
, AF_INET
, &ipv4_signature_len
, &ipv4_signature_flags
,
2486 (u_int8_t
*)&interface_details
.ipv4_signature
);
2488 u_int8_t ipv6_signature_len
= sizeof(interface_details
.ipv6_signature
);
2489 u_int16_t ipv6_signature_flags
;
2490 ifnet_get_netsignature(interface
, AF_INET6
, &ipv6_signature_len
, &ipv6_signature_flags
,
2491 (u_int8_t
*)&interface_details
.ipv6_signature
);
2496 error
= copyout(&interface_details
, uap
->buffer
, sizeof(interface_details
));
2498 NECPLOG(LOG_ERR
, "necp_client_copy_interface copyout error (%d)", error
);
2508 necp_client_stats_action(struct necp_client
*client
, user_addr_t buffer
, user_size_t buffer_size
)
2511 struct necp_stats_hdr
*stats_hdr
= NULL
;
2513 if (client
->stats_area
) {
2514 // Close old stats if required.
2515 if ((client
->stats_uaddr
!= buffer
) || (client
->stats_ulen
!= buffer_size
)) {
2516 necp_destroy_client_stats(client
);
2520 if ((buffer
== 0) || (buffer_size
== 0)) {
2524 if (client
->stats_area
) {
2526 error
= copyin(client
->stats_uaddr
, client
->stats_area
, client
->stats_ulen
);
2528 NECPLOG(LOG_ERR
, "necp_client_stats_action copyin error on update (%d)", error
);
2530 // Future use - check
2531 stats_hdr
= (necp_stats_hdr
*)client
->stats_area
;
2532 if (stats_hdr
->necp_stats_event
!= 0) {
2533 ntstat_userland_stats_event(client
->stats_handler_context
, (userland_stats_event_t
)stats_hdr
->necp_stats_event
);
2540 if ((buffer_size
> sizeof(necp_all_stats
)) || (buffer_size
< sizeof(necp_stats_hdr
))) {
2545 if ((stats_hdr
= _MALLOC(buffer_size
, M_NECP
, M_WAITOK
| M_ZERO
)) == NULL
) {
2550 client
->stats_handler_context
= NULL
;
2551 client
->stats_uaddr
= buffer
;
2552 client
->stats_ulen
= buffer_size
;
2553 client
->stats_area
= stats_hdr
;
2554 error
= copyin(client
->stats_uaddr
, client
->stats_area
, client
->stats_ulen
);
2556 NECPLOG(LOG_ERR
, "necp_client_stats_action copyin error on create (%d)", error
);
2560 switch (stats_hdr
->necp_stats_type
) {
2561 case NECP_CLIENT_STATISTICS_TYPE_TCP
: {
2562 if (stats_hdr
->necp_stats_ver
== NECP_CLIENT_STATISTICS_TYPE_TCP_VER_1
) {
2563 client
->stats_handler_context
= ntstat_userland_stats_open((userland_stats_provider_context
*)client
,
2564 NSTAT_PROVIDER_TCP_USERLAND
, 0, necp_request_tcp_netstats
);
2565 if (client
->stats_handler_context
== NULL
) {
2573 case NECP_CLIENT_STATISTICS_TYPE_UDP
: {
2574 if (stats_hdr
->necp_stats_ver
!= NECP_CLIENT_STATISTICS_TYPE_UDP_VER_1
) {
2575 client
->stats_handler_context
= ntstat_userland_stats_open((userland_stats_provider_context
*)client
,
2576 NSTAT_PROVIDER_UDP_USERLAND
, 0, necp_request_udp_netstats
);
2577 if (client
->stats_handler_context
== NULL
) {
2591 if ((error
) && (stats_hdr
!= NULL
)) {
2592 FREE(stats_hdr
, M_NECP
);
2593 client
->stats_area
= NULL
;
2594 client
->stats_handler_context
= NULL
;
2595 client
->stats_uaddr
= 0;
2596 client
->stats_ulen
= 0;
2603 necp_client_set_statistics(__unused
struct necp_fd_data
*fd_data
, struct necp_client_action_args
*uap
, int *retval
)
2606 struct necp_client
*find_client
= NULL
;
2607 struct necp_client
*client
= NULL
;
2610 if (uap
->client_id
== 0 || uap
->client_id_len
!= sizeof(uuid_t
)) {
2615 error
= copyin(uap
->client_id
, client_id
, sizeof(uuid_t
));
2617 NECPLOG(LOG_ERR
, "necp_client_set_statistics copyin client_id error (%d)", error
);
2621 lck_mtx_lock(&fd_data
->fd_lock
);
2622 LIST_FOREACH(find_client
, &fd_data
->clients
, chain
) {
2623 if (uuid_compare(find_client
->client_id
, client_id
) == 0) {
2624 client
= find_client
;
2630 error
= necp_client_stats_action(client
, uap
->buffer
, uap
->buffer_size
);
2634 lck_mtx_unlock(&fd_data
->fd_lock
);
2641 necp_client_action(struct proc
*p
, struct necp_client_action_args
*uap
, int *retval
)
2645 int return_value
= 0;
2646 struct necp_fd_data
*fd_data
= NULL
;
2647 error
= necp_find_fd_data(uap
->necp_fd
, &fd_data
);
2649 NECPLOG(LOG_ERR
, "necp_client_action find fd error (%d)", error
);
2653 u_int32_t action
= uap
->action
;
2655 case NECP_CLIENT_ACTION_ADD
: {
2656 return_value
= necp_client_add(fd_data
, uap
, retval
);
2659 case NECP_CLIENT_ACTION_REMOVE
: {
2660 return_value
= necp_client_remove(fd_data
, uap
, retval
);
2663 case NECP_CLIENT_ACTION_COPY_PARAMETERS
:
2664 case NECP_CLIENT_ACTION_COPY_RESULT
: {
2665 return_value
= necp_client_copy(fd_data
, uap
, retval
);
2668 case NECP_CLIENT_ACTION_COPY_LIST
: {
2669 return_value
= necp_client_list(fd_data
, uap
, retval
);
2672 case NECP_CLIENT_ACTION_REQUEST_NEXUS_INSTANCE
: {
2673 return_value
= necp_client_request_nexus(fd_data
, uap
, retval
);
2676 case NECP_CLIENT_ACTION_AGENT
: {
2677 return_value
= necp_client_agent_action(fd_data
, uap
, retval
);
2680 case NECP_CLIENT_ACTION_COPY_AGENT
: {
2681 return_value
= necp_client_copy_agent(fd_data
, uap
, retval
);
2684 case NECP_CLIENT_ACTION_AGENT_USE
: {
2685 return_value
= necp_client_agent_use(fd_data
, uap
, retval
);
2688 case NECP_CLIENT_ACTION_COPY_INTERFACE
: {
2689 return_value
= necp_client_copy_interface(fd_data
, uap
, retval
);
2692 case NECP_CLIENT_ACTION_SET_STATISTICS
: {
2693 return_value
= necp_client_set_statistics(fd_data
, uap
, retval
);
2697 NECPLOG(LOG_ERR
, "necp_client_action unknown action (%u)", action
);
2698 return_value
= EINVAL
;
2703 file_drop(uap
->necp_fd
);
2705 return (return_value
);
2708 #define NECP_MAX_MATCH_POLICY_PARAMETER_SIZE 1024
2711 necp_match_policy(struct proc
*p
, struct necp_match_policy_args
*uap
, int32_t *retval
)
2713 #pragma unused(retval)
2714 u_int8_t
*parameters
= NULL
;
2715 struct necp_aggregate_result returned_result
;
2723 if (uap
->parameters
== 0 || uap
->parameters_size
== 0 || uap
->parameters_size
> NECP_MAX_MATCH_POLICY_PARAMETER_SIZE
|| uap
->returned_result
== 0) {
2728 MALLOC(parameters
, u_int8_t
*, uap
->parameters_size
, M_NECP
, M_WAITOK
| M_ZERO
);
2729 if (parameters
== NULL
) {
2733 // Copy parameters in
2734 error
= copyin(uap
->parameters
, parameters
, uap
->parameters_size
);
2739 error
= necp_application_find_policy_match_internal(p
, parameters
, uap
->parameters_size
, &returned_result
, NULL
, 0);
2744 // Copy return value back
2745 error
= copyout(&returned_result
, uap
->returned_result
, sizeof(struct necp_aggregate_result
));
2750 if (parameters
!= NULL
) {
2751 FREE(parameters
, M_NECP
);
2756 /// Socket operations
2757 #define NECP_MAX_SOCKET_ATTRIBUTE_STRING_LENGTH 253
2760 necp_set_socket_attribute(u_int8_t
*buffer
, size_t buffer_length
, u_int8_t type
, char **buffer_p
)
2764 size_t string_size
= 0;
2765 char *local_string
= NULL
;
2766 u_int8_t
*value
= NULL
;
2768 cursor
= necp_buffer_find_tlv(buffer
, buffer_length
, 0, type
, 0);
2770 // This will clear out the parameter
2774 string_size
= necp_buffer_get_tlv_length(buffer
, cursor
);
2775 if (string_size
== 0 || string_size
> NECP_MAX_SOCKET_ATTRIBUTE_STRING_LENGTH
) {
2776 // This will clear out the parameter
2780 MALLOC(local_string
, char *, string_size
+ 1, M_NECP
, M_WAITOK
| M_ZERO
);
2781 if (local_string
== NULL
) {
2782 NECPLOG(LOG_ERR
, "Failed to allocate a socket attribute buffer (size %d)", string_size
);
2786 value
= necp_buffer_get_tlv_value(buffer
, cursor
, NULL
);
2787 if (value
== NULL
) {
2788 NECPLOG0(LOG_ERR
, "Failed to get socket attribute");
2792 memcpy(local_string
, value
, string_size
);
2793 local_string
[string_size
] = 0;
2796 if (*buffer_p
!= NULL
) {
2797 FREE(*buffer_p
, M_NECP
);
2801 *buffer_p
= local_string
;
2804 if (local_string
!= NULL
) {
2805 FREE(local_string
, M_NECP
);
2811 necp_set_socket_attributes(struct socket
*so
, struct sockopt
*sopt
)
2814 u_int8_t
*buffer
= NULL
;
2815 struct inpcb
*inp
= NULL
;
2817 if ((SOCK_DOM(so
) != PF_INET
2819 && SOCK_DOM(so
) != PF_INET6
2826 inp
= sotoinpcb(so
);
2828 size_t valsize
= sopt
->sopt_valsize
;
2830 valsize
> ((sizeof(u_int8_t
) + sizeof(u_int32_t
) + NECP_MAX_SOCKET_ATTRIBUTE_STRING_LENGTH
) * 2)) {
2834 MALLOC(buffer
, u_int8_t
*, valsize
, M_NECP
, M_WAITOK
| M_ZERO
);
2835 if (buffer
== NULL
) {
2839 error
= sooptcopyin(sopt
, buffer
, valsize
, 0);
2844 error
= necp_set_socket_attribute(buffer
, valsize
, NECP_TLV_ATTRIBUTE_DOMAIN
, &inp
->inp_necp_attributes
.inp_domain
);
2846 NECPLOG0(LOG_ERR
, "Could not set domain TLV for socket attributes");
2850 error
= necp_set_socket_attribute(buffer
, valsize
, NECP_TLV_ATTRIBUTE_ACCOUNT
, &inp
->inp_necp_attributes
.inp_account
);
2852 NECPLOG0(LOG_ERR
, "Could not set account TLV for socket attributes");
2857 NECPLOG(LOG_DEBUG
, "Set on socket: Domain %s, Account %s", inp
->inp_necp_attributes
.inp_domain
, inp
->inp_necp_attributes
.inp_account
);
2860 if (buffer
!= NULL
) {
2861 FREE(buffer
, M_NECP
);
2868 necp_get_socket_attributes(struct socket
*so
, struct sockopt
*sopt
)
2871 u_int8_t
*buffer
= NULL
;
2872 u_int8_t
*cursor
= NULL
;
2874 struct inpcb
*inp
= sotoinpcb(so
);
2876 if (inp
->inp_necp_attributes
.inp_domain
!= NULL
) {
2877 valsize
+= sizeof(u_int8_t
) + sizeof(u_int32_t
) + strlen(inp
->inp_necp_attributes
.inp_domain
);
2879 if (inp
->inp_necp_attributes
.inp_account
!= NULL
) {
2880 valsize
+= sizeof(u_int8_t
) + sizeof(u_int32_t
) + strlen(inp
->inp_necp_attributes
.inp_account
);
2886 MALLOC(buffer
, u_int8_t
*, valsize
, M_NECP
, M_WAITOK
| M_ZERO
);
2887 if (buffer
== NULL
) {
2892 if (inp
->inp_necp_attributes
.inp_domain
!= NULL
) {
2893 cursor
= necp_buffer_write_tlv(cursor
, NECP_TLV_ATTRIBUTE_DOMAIN
, strlen(inp
->inp_necp_attributes
.inp_domain
), inp
->inp_necp_attributes
.inp_domain
);
2896 if (inp
->inp_necp_attributes
.inp_account
!= NULL
) {
2897 cursor
= necp_buffer_write_tlv(cursor
, NECP_TLV_ATTRIBUTE_ACCOUNT
, strlen(inp
->inp_necp_attributes
.inp_account
), inp
->inp_necp_attributes
.inp_account
);
2900 error
= sooptcopyout(sopt
, buffer
, valsize
);
2905 if (buffer
!= NULL
) {
2906 FREE(buffer
, M_NECP
);
2913 necp_inpcb_dispose(struct inpcb
*inp
)
2915 if (inp
->inp_necp_attributes
.inp_domain
!= NULL
) {
2916 FREE(inp
->inp_necp_attributes
.inp_domain
, M_NECP
);
2917 inp
->inp_necp_attributes
.inp_domain
= NULL
;
2919 if (inp
->inp_necp_attributes
.inp_account
!= NULL
) {
2920 FREE(inp
->inp_necp_attributes
.inp_account
, M_NECP
);
2921 inp
->inp_necp_attributes
.inp_account
= NULL
;
2928 necp_client_init(void)
2932 necp_fd_grp_attr
= lck_grp_attr_alloc_init();
2933 if (necp_fd_grp_attr
== NULL
) {
2934 NECPLOG0(LOG_ERR
, "lck_grp_attr_alloc_init failed");
2939 necp_fd_mtx_grp
= lck_grp_alloc_init("necp_fd", necp_fd_grp_attr
);
2940 if (necp_fd_mtx_grp
== NULL
) {
2941 NECPLOG0(LOG_ERR
, "lck_grp_alloc_init failed");
2946 necp_fd_mtx_attr
= lck_attr_alloc_init();
2947 if (necp_fd_mtx_attr
== NULL
) {
2948 NECPLOG0(LOG_ERR
, "lck_attr_alloc_init failed");
2953 necp_client_tcall
= thread_call_allocate(necp_update_all_clients_callout
, NULL
);
2954 if (necp_client_tcall
== NULL
) {
2955 NECPLOG0(LOG_ERR
, "thread_call_allocate failed");
2960 lck_rw_init(&necp_fd_lock
, necp_fd_mtx_grp
, necp_fd_mtx_attr
);
2962 LIST_INIT(&necp_fd_list
);
2966 if (necp_fd_mtx_attr
!= NULL
) {
2967 lck_attr_free(necp_fd_mtx_attr
);
2968 necp_fd_mtx_attr
= NULL
;
2970 if (necp_fd_mtx_grp
!= NULL
) {
2971 lck_grp_free(necp_fd_mtx_grp
);
2972 necp_fd_mtx_grp
= NULL
;
2974 if (necp_fd_grp_attr
!= NULL
) {
2975 lck_grp_attr_free(necp_fd_grp_attr
);
2976 necp_fd_grp_attr
= NULL
;