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
> 0 && (offset
+ sizeof(u_int8_t
) + sizeof(u_int32_t
) + length
) <= parameters_size
) {
660 u_int8_t
*value
= necp_buffer_get_tlv_value(parameters
, offset
, NULL
);
663 case NECP_CLIENT_PARAMETER_BOUND_INTERFACE
: {
664 if (length
<= IFXNAMSIZ
&& length
> 0) {
665 ifnet_t bound_interface
= NULL
;
666 char interface_name
[IFXNAMSIZ
];
667 memcpy(interface_name
, value
, length
);
668 interface_name
[length
- 1] = 0; // Make sure the string is NULL terminated
669 if (ifnet_find_by_name(interface_name
, &bound_interface
) == 0) {
670 parsed_parameters
->required_interface_index
= bound_interface
->if_index
;
671 parsed_parameters
->valid_fields
|= NECP_PARSED_PARAMETERS_FIELD_REQUIRED_IF
;
672 ifnet_release(bound_interface
);
677 case NECP_CLIENT_PARAMETER_LOCAL_ADDRESS
: {
678 if (length
>= sizeof(struct necp_policy_condition_addr
)) {
679 struct necp_policy_condition_addr
*address_struct
= (struct necp_policy_condition_addr
*)(void *)value
;
680 if ((address_struct
->address
.sa
.sa_family
== AF_INET
||
681 address_struct
->address
.sa
.sa_family
== AF_INET6
) &&
682 address_struct
->address
.sa
.sa_len
<= length
) {
683 memcpy(&parsed_parameters
->local_addr
, &address_struct
->address
, sizeof(address_struct
->address
));
684 parsed_parameters
->valid_fields
|= NECP_PARSED_PARAMETERS_FIELD_LOCAL_ADDR
;
689 case NECP_CLIENT_PARAMETER_LOCAL_ENDPOINT
: {
690 if (length
>= sizeof(struct necp_client_endpoint
)) {
691 struct necp_client_endpoint
*endpoint
= (struct necp_client_endpoint
*)(void *)value
;
692 if ((endpoint
->u
.endpoint
.endpoint_family
== AF_INET
||
693 endpoint
->u
.endpoint
.endpoint_family
== AF_INET6
) &&
694 endpoint
->u
.endpoint
.endpoint_length
<= length
) {
695 memcpy(&parsed_parameters
->local_addr
, &endpoint
->u
.sa
, sizeof(union necp_sockaddr_union
));
696 parsed_parameters
->valid_fields
|= NECP_PARSED_PARAMETERS_FIELD_LOCAL_ADDR
;
701 case NECP_CLIENT_PARAMETER_REMOTE_ADDRESS
: {
702 if (length
>= sizeof(struct necp_policy_condition_addr
)) {
703 struct necp_policy_condition_addr
*address_struct
= (struct necp_policy_condition_addr
*)(void *)value
;
704 if ((address_struct
->address
.sa
.sa_family
== AF_INET
||
705 address_struct
->address
.sa
.sa_family
== AF_INET6
) &&
706 address_struct
->address
.sa
.sa_len
<= length
) {
707 memcpy(&parsed_parameters
->remote_addr
, &address_struct
->address
, sizeof(address_struct
->address
));
708 parsed_parameters
->valid_fields
|= NECP_PARSED_PARAMETERS_FIELD_REMOTE_ADDR
;
713 case NECP_CLIENT_PARAMETER_REMOTE_ENDPOINT
: {
714 if (length
>= sizeof(struct necp_client_endpoint
)) {
715 struct necp_client_endpoint
*endpoint
= (struct necp_client_endpoint
*)(void *)value
;
716 if ((endpoint
->u
.endpoint
.endpoint_family
== AF_INET
||
717 endpoint
->u
.endpoint
.endpoint_family
== AF_INET6
) &&
718 endpoint
->u
.endpoint
.endpoint_length
<= length
) {
719 memcpy(&parsed_parameters
->remote_addr
, &endpoint
->u
.sa
, sizeof(union necp_sockaddr_union
));
720 parsed_parameters
->valid_fields
|= NECP_PARSED_PARAMETERS_FIELD_REMOTE_ADDR
;
725 case NECP_CLIENT_PARAMETER_PROHIBIT_INTERFACE
: {
726 if (num_prohibited_interfaces
>= NECP_MAX_PARSED_PARAMETERS
) {
729 if (length
<= IFXNAMSIZ
&& length
> 0) {
730 memcpy(parsed_parameters
->prohibited_interfaces
[num_prohibited_interfaces
], value
, length
);
731 parsed_parameters
->prohibited_interfaces
[num_prohibited_interfaces
][length
- 1] = 0; // Make sure the string is NULL terminated
732 num_prohibited_interfaces
++;
733 parsed_parameters
->valid_fields
|= NECP_PARSED_PARAMETERS_FIELD_PROHIBITED_IF
;
737 case NECP_CLIENT_PARAMETER_REQUIRE_IF_TYPE
: {
738 if (num_required_interface_types
>= NECP_MAX_PARSED_PARAMETERS
) {
741 if (length
>= sizeof(u_int8_t
)) {
742 memcpy(&parsed_parameters
->required_interface_types
[num_required_interface_types
], value
, sizeof(u_int8_t
));
743 num_required_interface_types
++;
744 parsed_parameters
->valid_fields
|= NECP_PARSED_PARAMETERS_FIELD_REQUIRED_IFTYPE
;
748 case NECP_CLIENT_PARAMETER_PROHIBIT_IF_TYPE
: {
749 if (num_prohibited_interface_types
>= NECP_MAX_PARSED_PARAMETERS
) {
752 if (length
>= sizeof(u_int8_t
)) {
753 memcpy(&parsed_parameters
->prohibited_interface_types
[num_prohibited_interface_types
], value
, sizeof(u_int8_t
));
754 num_prohibited_interface_types
++;
755 parsed_parameters
->valid_fields
|= NECP_PARSED_PARAMETERS_FIELD_PROHIBITED_IFTYPE
;
759 case NECP_CLIENT_PARAMETER_REQUIRE_AGENT
: {
760 if (num_required_agents
>= NECP_MAX_PARSED_PARAMETERS
) {
763 if (length
>= sizeof(uuid_t
)) {
764 memcpy(&parsed_parameters
->required_netagents
[num_required_agents
], value
, sizeof(uuid_t
));
765 num_required_agents
++;
766 parsed_parameters
->valid_fields
|= NECP_PARSED_PARAMETERS_FIELD_REQUIRED_AGENT
;
770 case NECP_CLIENT_PARAMETER_PROHIBIT_AGENT
: {
771 if (num_prohibited_agents
>= NECP_MAX_PARSED_PARAMETERS
) {
774 if (length
>= sizeof(uuid_t
)) {
775 memcpy(&parsed_parameters
->prohibited_netagents
[num_prohibited_agents
], value
, sizeof(uuid_t
));
776 num_prohibited_agents
++;
777 parsed_parameters
->valid_fields
|= NECP_PARSED_PARAMETERS_FIELD_PROHIBITED_AGENT
;
781 case NECP_CLIENT_PARAMETER_PREFER_AGENT
: {
782 if (num_preferred_agents
>= NECP_MAX_PARSED_PARAMETERS
) {
785 if (length
>= sizeof(uuid_t
)) {
786 memcpy(&parsed_parameters
->preferred_netagents
[num_preferred_agents
], value
, sizeof(uuid_t
));
787 num_preferred_agents
++;
788 parsed_parameters
->valid_fields
|= NECP_PARSED_PARAMETERS_FIELD_PREFERRED_AGENT
;
792 case NECP_CLIENT_PARAMETER_REQUIRE_AGENT_TYPE
: {
793 if (num_required_agent_types
>= NECP_MAX_PARSED_PARAMETERS
) {
796 if (length
>= sizeof(struct necp_client_parameter_netagent_type
)) {
797 memcpy(&parsed_parameters
->required_netagent_types
[num_required_agent_types
], value
, sizeof(struct necp_client_parameter_netagent_type
));
798 num_required_agent_types
++;
799 parsed_parameters
->valid_fields
|= NECP_PARSED_PARAMETERS_FIELD_REQUIRED_AGENT_TYPE
;
803 case NECP_CLIENT_PARAMETER_PROHIBIT_AGENT_TYPE
: {
804 if (num_prohibited_agent_types
>= NECP_MAX_PARSED_PARAMETERS
) {
807 if (length
>= sizeof(struct necp_client_parameter_netagent_type
)) {
808 memcpy(&parsed_parameters
->prohibited_netagent_types
[num_prohibited_agent_types
], value
, sizeof(struct necp_client_parameter_netagent_type
));
809 num_prohibited_agent_types
++;
810 parsed_parameters
->valid_fields
|= NECP_PARSED_PARAMETERS_FIELD_PROHIBITED_AGENT_TYPE
;
814 case NECP_CLIENT_PARAMETER_PREFER_AGENT_TYPE
: {
815 if (num_preferred_agent_types
>= NECP_MAX_PARSED_PARAMETERS
) {
818 if (length
>= sizeof(struct necp_client_parameter_netagent_type
)) {
819 memcpy(&parsed_parameters
->preferred_netagent_types
[num_preferred_agent_types
], value
, sizeof(struct necp_client_parameter_netagent_type
));
820 num_preferred_agent_types
++;
821 parsed_parameters
->valid_fields
|= NECP_PARSED_PARAMETERS_FIELD_PREFERRED_AGENT_TYPE
;
832 offset
+= sizeof(u_int8_t
) + sizeof(u_int32_t
) + length
;
839 necp_assign_client_result(uuid_t netagent_uuid
, uuid_t client_id
,
840 u_int8_t
*assigned_results
, size_t assigned_results_length
)
843 struct necp_fd_data
*client_fd
= NULL
;
844 bool found_client
= FALSE
;
845 bool client_updated
= FALSE
;
847 lck_rw_lock_shared(&necp_fd_lock
);
849 LIST_FOREACH(client_fd
, &necp_fd_list
, chain
) {
850 struct necp_client
*client
= NULL
;
851 lck_mtx_lock(&client_fd
->fd_lock
);
852 LIST_FOREACH(client
, &client_fd
->clients
, chain
) {
853 if (uuid_compare(client
->client_id
, client_id
) == 0) {
854 // Found the right client!
857 if (uuid_compare(client
->nexus_agent
, netagent_uuid
) == 0) {
858 // Verify that the client nexus agent matches
859 if (client
->assigned_results
!= NULL
) {
860 // Release prior result
861 FREE(client
->assigned_results
, M_NETAGENT
);
863 client
->assigned_results
= assigned_results
;
864 client
->assigned_results_length
= assigned_results_length
;
865 client
->assigned_result_read
= FALSE
;
866 client_updated
= TRUE
;
870 if (client_updated
) {
871 necp_fd_notify(client_fd
, true);
873 lck_mtx_unlock(&client_fd
->fd_lock
);
880 lck_rw_done(&necp_fd_lock
);
884 } else if (!client_updated
) {
894 necp_update_client_result(proc_t proc
,
895 struct necp_client
*client
)
897 struct necp_client_result_netagent netagent
;
898 struct necp_aggregate_result result
;
899 struct necp_client_parsed_parameters parsed_parameters
;
902 uuid_clear(client
->nexus_agent
);
904 int error
= necp_client_parse_parameters(client
->parameters
, (u_int32_t
)client
->parameters_length
, &parsed_parameters
);
909 // Check parameters to find best interface
910 u_int matching_if_index
= 0;
911 if (necp_find_matching_interface_index(&parsed_parameters
, &matching_if_index
)) {
912 if (matching_if_index
!= 0) {
913 parsed_parameters
.required_interface_index
= matching_if_index
;
915 // Interface found or not needed, match policy.
916 error
= necp_application_find_policy_match_internal(proc
, client
->parameters
, (u_int32_t
)client
->parameters_length
, &result
, &flags
, matching_if_index
);
921 // Interface not found. Clear out the whole result, make everything fail.
922 memset(&result
, 0, sizeof(result
));
925 // If the original request was scoped, and the policy result matches, make sure the result is scoped
926 if ((result
.routing_result
== NECP_KERNEL_POLICY_RESULT_NONE
||
927 result
.routing_result
== NECP_KERNEL_POLICY_RESULT_PASS
) &&
928 result
.routed_interface_index
!= IFSCOPE_NONE
&&
929 parsed_parameters
.required_interface_index
== result
.routed_interface_index
) {
930 result
.routing_result
= NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED
;
931 result
.routing_result_parameter
.scoped_interface_index
= result
.routed_interface_index
;
934 bool updated
= FALSE
;
935 u_int8_t
*cursor
= client
->result
;
936 const u_int8_t
*max
= client
->result
+ NECP_MAX_CLIENT_RESULT_SIZE
;
937 cursor
= necp_buffer_write_tlv_if_different(cursor
, max
, NECP_CLIENT_RESULT_CLIENT_ID
, sizeof(uuid_t
), client
->client_id
, &updated
);
938 cursor
= necp_buffer_write_tlv_if_different(cursor
, max
, NECP_CLIENT_RESULT_POLICY_RESULT
, sizeof(result
.routing_result
), &result
.routing_result
, &updated
);
939 if (result
.routing_result_parameter
.tunnel_interface_index
!= 0) {
940 cursor
= necp_buffer_write_tlv_if_different(cursor
, max
, NECP_CLIENT_RESULT_POLICY_RESULT_PARAMETER
,
941 sizeof(result
.routing_result_parameter
), &result
.routing_result_parameter
, &updated
);
943 if (result
.filter_control_unit
!= 0) {
944 cursor
= necp_buffer_write_tlv_if_different(cursor
, max
, NECP_CLIENT_RESULT_FILTER_CONTROL_UNIT
,
945 sizeof(result
.filter_control_unit
), &result
.filter_control_unit
, &updated
);
947 if (result
.routed_interface_index
!= 0) {
948 u_int routed_interface_index
= result
.routed_interface_index
;
949 if (result
.routing_result
== NECP_KERNEL_POLICY_RESULT_IP_TUNNEL
&&
950 parsed_parameters
.required_interface_index
!= IFSCOPE_NONE
&&
951 parsed_parameters
.required_interface_index
!= result
.routed_interface_index
) {
952 routed_interface_index
= parsed_parameters
.required_interface_index
;
955 cursor
= necp_buffer_write_tlv_if_different(cursor
, max
, NECP_CLIENT_RESULT_INTERFACE_INDEX
,
956 sizeof(routed_interface_index
), &routed_interface_index
, &updated
);
959 cursor
= necp_buffer_write_tlv_if_different(cursor
, max
, NECP_CLIENT_RESULT_FLAGS
,
960 sizeof(flags
), &flags
, &updated
);
962 for (int i
= 0; i
< NECP_MAX_NETAGENTS
; i
++) {
963 if (uuid_is_null(result
.netagents
[i
])) {
966 uuid_copy(netagent
.netagent_uuid
, result
.netagents
[i
]);
967 netagent
.generation
= netagent_get_generation(netagent
.netagent_uuid
);
968 if (necp_netagent_applies_to_client(client
, &parsed_parameters
, netagent
.netagent_uuid
)) {
969 cursor
= necp_buffer_write_tlv_if_different(cursor
, max
, NECP_CLIENT_RESULT_NETAGENT
, sizeof(netagent
), &netagent
, &updated
);
973 ifnet_head_lock_shared();
974 ifnet_t direct_interface
= NULL
;
975 ifnet_t delegate_interface
= NULL
;
976 ifnet_t original_scoped_interface
= NULL
;
978 if (result
.routed_interface_index
!= IFSCOPE_NONE
&& (int)result
.routed_interface_index
<= if_index
) {
979 direct_interface
= ifindex2ifnet
[result
.routed_interface_index
];
980 } else if (parsed_parameters
.required_interface_index
!= IFSCOPE_NONE
&&
981 (int)parsed_parameters
.required_interface_index
<= if_index
) {
982 // If the request was scoped, but the route didn't match, still grab the agents
983 direct_interface
= ifindex2ifnet
[parsed_parameters
.required_interface_index
];
984 } else if (result
.routed_interface_index
== IFSCOPE_NONE
&&
985 result
.routing_result
== NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED
&&
986 result
.routing_result_parameter
.scoped_interface_index
!= IFSCOPE_NONE
) {
987 direct_interface
= ifindex2ifnet
[result
.routing_result_parameter
.scoped_interface_index
];
989 if (direct_interface
!= NULL
) {
990 delegate_interface
= direct_interface
->if_delegated
.ifp
;
992 if (result
.routing_result
== NECP_KERNEL_POLICY_RESULT_IP_TUNNEL
&&
993 parsed_parameters
.required_interface_index
!= IFSCOPE_NONE
&&
994 parsed_parameters
.required_interface_index
!= result
.routing_result_parameter
.tunnel_interface_index
&&
995 (int)parsed_parameters
.required_interface_index
<= if_index
) {
996 original_scoped_interface
= ifindex2ifnet
[parsed_parameters
.required_interface_index
];
999 if (original_scoped_interface
!= NULL
) {
1000 struct necp_client_result_interface interface_struct
;
1001 interface_struct
.index
= original_scoped_interface
->if_index
;
1002 interface_struct
.generation
= ifnet_get_generation(original_scoped_interface
);
1003 cursor
= necp_buffer_write_tlv_if_different(cursor
, max
, NECP_CLIENT_RESULT_INTERFACE
, sizeof(interface_struct
), &interface_struct
, &updated
);
1005 if (direct_interface
!= NULL
) {
1006 struct necp_client_result_interface interface_struct
;
1007 interface_struct
.index
= direct_interface
->if_index
;
1008 interface_struct
.generation
= ifnet_get_generation(direct_interface
);
1009 cursor
= necp_buffer_write_tlv_if_different(cursor
, max
, NECP_CLIENT_RESULT_INTERFACE
, sizeof(interface_struct
), &interface_struct
, &updated
);
1011 if (delegate_interface
!= NULL
) {
1012 struct necp_client_result_interface interface_struct
;
1013 interface_struct
.index
= delegate_interface
->if_index
;
1014 interface_struct
.generation
= ifnet_get_generation(delegate_interface
);
1015 cursor
= necp_buffer_write_tlv_if_different(cursor
, max
, NECP_CLIENT_RESULT_INTERFACE
, sizeof(interface_struct
), &interface_struct
, &updated
);
1018 if (original_scoped_interface
!= NULL
) {
1019 ifnet_lock_shared(original_scoped_interface
);
1020 if (original_scoped_interface
->if_agentids
!= NULL
) {
1021 for (u_int32_t i
= 0; i
< original_scoped_interface
->if_agentcount
; i
++) {
1022 if (uuid_is_null(original_scoped_interface
->if_agentids
[i
])) {
1025 uuid_copy(netagent
.netagent_uuid
, original_scoped_interface
->if_agentids
[i
]);
1026 netagent
.generation
= netagent_get_generation(netagent
.netagent_uuid
);
1027 if (necp_netagent_applies_to_client(client
, &parsed_parameters
, netagent
.netagent_uuid
)) {
1028 cursor
= necp_buffer_write_tlv_if_different(cursor
, max
, NECP_CLIENT_RESULT_NETAGENT
, sizeof(netagent
), &netagent
, &updated
);
1032 ifnet_lock_done(original_scoped_interface
);
1034 if (direct_interface
!= NULL
) {
1035 ifnet_lock_shared(direct_interface
);
1036 if (direct_interface
->if_agentids
!= NULL
) {
1037 for (u_int32_t i
= 0; i
< direct_interface
->if_agentcount
; i
++) {
1038 if (uuid_is_null(direct_interface
->if_agentids
[i
])) {
1041 uuid_copy(netagent
.netagent_uuid
, direct_interface
->if_agentids
[i
]);
1042 netagent
.generation
= netagent_get_generation(netagent
.netagent_uuid
);
1043 if (necp_netagent_applies_to_client(client
, &parsed_parameters
, netagent
.netagent_uuid
)) {
1044 cursor
= necp_buffer_write_tlv_if_different(cursor
, max
, NECP_CLIENT_RESULT_NETAGENT
, sizeof(netagent
), &netagent
, &updated
);
1048 ifnet_lock_done(direct_interface
);
1050 if (delegate_interface
!= NULL
) {
1051 ifnet_lock_shared(delegate_interface
);
1052 if (delegate_interface
->if_agentids
!= NULL
) {
1053 for (u_int32_t i
= 0; i
< delegate_interface
->if_agentcount
; i
++) {
1054 if (uuid_is_null(delegate_interface
->if_agentids
[i
])) {
1057 uuid_copy(netagent
.netagent_uuid
, delegate_interface
->if_agentids
[i
]);
1058 netagent
.generation
= netagent_get_generation(netagent
.netagent_uuid
);
1059 if (necp_netagent_applies_to_client(client
, &parsed_parameters
, netagent
.netagent_uuid
)) {
1060 cursor
= necp_buffer_write_tlv_if_different(cursor
, max
, NECP_CLIENT_RESULT_NETAGENT
, sizeof(netagent
), &netagent
, &updated
);
1064 ifnet_lock_done(delegate_interface
);
1068 size_t new_result_length
= (cursor
- client
->result
);
1069 if (new_result_length
!= client
->result_length
) {
1070 client
->result_length
= new_result_length
;
1074 client
->result_read
= FALSE
;
1081 necp_update_all_clients_callout(__unused thread_call_param_t dummy
,
1082 __unused thread_call_param_t arg
)
1085 struct necp_fd_data
*client_fd
= NULL
;
1087 lck_rw_lock_shared(&necp_fd_lock
);
1089 LIST_FOREACH(client_fd
, &necp_fd_list
, chain
) {
1090 bool updated_result
= FALSE
;
1091 struct necp_client
*client
= NULL
;
1092 proc_t proc
= proc_find(client_fd
->proc_pid
);
1097 lck_mtx_lock(&client_fd
->fd_lock
);
1098 LIST_FOREACH(client
, &client_fd
->clients
, chain
) {
1099 if (necp_update_client_result(proc
, client
)) {
1100 updated_result
= TRUE
;
1103 if (updated_result
) {
1104 necp_fd_notify(client_fd
, true);
1106 lck_mtx_unlock(&client_fd
->fd_lock
);
1111 lck_rw_done(&necp_fd_lock
);
1115 necp_update_all_clients(void)
1117 if (necp_client_tcall
== NULL
) {
1118 // Don't try to update clients if the module is not initialized
1122 uint64_t deadline
= 0;
1123 uint64_t leeway
= 0;
1124 clock_interval_to_deadline(necp_timeout_microseconds
, NSEC_PER_USEC
, &deadline
);
1125 clock_interval_to_absolutetime_interval(necp_timeout_leeway_microseconds
, NSEC_PER_USEC
, &leeway
);
1127 thread_call_enter_delayed_with_leeway(necp_client_tcall
, NULL
,
1128 deadline
, leeway
, THREAD_CALL_DELAY_LEEWAY
);
1132 necp_client_remove_agent_from_result(struct necp_client
*client
, uuid_t netagent_uuid
)
1136 u_int8_t
*result_buffer
= client
->result
;
1137 while ((offset
+ sizeof(u_int8_t
) + sizeof(u_int32_t
)) <= client
->result_length
) {
1138 u_int8_t type
= necp_buffer_get_tlv_type(result_buffer
, offset
);
1139 u_int32_t length
= necp_buffer_get_tlv_length(result_buffer
, offset
);
1141 size_t tlv_total_length
= (sizeof(u_int8_t
) + sizeof(u_int32_t
) + length
);
1142 if (type
== NECP_CLIENT_RESULT_NETAGENT
&&
1143 length
== sizeof(struct necp_client_result_netagent
) &&
1144 (offset
+ tlv_total_length
) <= client
->result_length
) {
1145 struct necp_client_result_netagent
*value
= ((struct necp_client_result_netagent
*)(void *)
1146 necp_buffer_get_tlv_value(result_buffer
, offset
, NULL
));
1147 if (uuid_compare(value
->netagent_uuid
, netagent_uuid
) == 0) {
1148 // Found a netagent to remove
1149 // Shift bytes down to remove the tlv, and adjust total length
1150 // Don't adjust the current offset
1151 memmove(result_buffer
+ offset
,
1152 result_buffer
+ offset
+ tlv_total_length
,
1153 client
->result_length
- (offset
+ tlv_total_length
));
1154 client
->result_length
-= tlv_total_length
;
1155 memset(result_buffer
+ client
->result_length
, 0, NECP_MAX_CLIENT_RESULT_SIZE
- client
->result_length
);
1160 offset
+= tlv_total_length
;
1165 necp_force_update_client(uuid_t client_id
, uuid_t remove_netagent_uuid
)
1167 struct necp_fd_data
*client_fd
= NULL
;
1169 lck_rw_lock_shared(&necp_fd_lock
);
1171 LIST_FOREACH(client_fd
, &necp_fd_list
, chain
) {
1172 bool updated_result
= FALSE
;
1173 struct necp_client
*client
= NULL
;
1174 lck_mtx_lock(&client_fd
->fd_lock
);
1175 LIST_FOREACH(client
, &client_fd
->clients
, chain
) {
1176 if (uuid_compare(client
->client_id
, client_id
) == 0) {
1177 if (!uuid_is_null(remove_netagent_uuid
)) {
1178 necp_client_remove_agent_from_result(client
, remove_netagent_uuid
);
1180 client
->assigned_result_read
= FALSE
;
1181 updated_result
= TRUE
;
1182 // Found the client, break
1186 if (updated_result
) {
1187 necp_fd_notify(client_fd
, true);
1189 lck_mtx_unlock(&client_fd
->fd_lock
);
1190 if (updated_result
) {
1191 // Found the client, break
1196 lck_rw_done(&necp_fd_lock
);
1199 /// Interface matching
1201 #define NECP_PARSED_PARAMETERS_INTERESTING_IFNET_FIELDS (NECP_PARSED_PARAMETERS_FIELD_LOCAL_ADDR | \
1202 NECP_PARSED_PARAMETERS_FIELD_PROHIBITED_IF | \
1203 NECP_PARSED_PARAMETERS_FIELD_REQUIRED_IFTYPE | \
1204 NECP_PARSED_PARAMETERS_FIELD_PROHIBITED_IFTYPE | \
1205 NECP_PARSED_PARAMETERS_FIELD_REQUIRED_AGENT | \
1206 NECP_PARSED_PARAMETERS_FIELD_PROHIBITED_AGENT | \
1207 NECP_PARSED_PARAMETERS_FIELD_PREFERRED_AGENT | \
1208 NECP_PARSED_PARAMETERS_FIELD_REQUIRED_AGENT_TYPE | \
1209 NECP_PARSED_PARAMETERS_FIELD_PROHIBITED_AGENT_TYPE | \
1210 NECP_PARSED_PARAMETERS_FIELD_PREFERRED_AGENT_TYPE)
1212 #define NECP_PARSED_PARAMETERS_SCOPED_IFNET_FIELDS (NECP_PARSED_PARAMETERS_FIELD_LOCAL_ADDR | \
1213 NECP_PARSED_PARAMETERS_FIELD_REQUIRED_IFTYPE | \
1214 NECP_PARSED_PARAMETERS_FIELD_REQUIRED_AGENT | \
1215 NECP_PARSED_PARAMETERS_FIELD_PREFERRED_AGENT | \
1216 NECP_PARSED_PARAMETERS_FIELD_REQUIRED_AGENT_TYPE | \
1217 NECP_PARSED_PARAMETERS_FIELD_PREFERRED_AGENT_TYPE)
1219 #define NECP_PARSED_PARAMETERS_PREFERRED_IFNET_FIELDS (NECP_PARSED_PARAMETERS_FIELD_PREFERRED_AGENT | \
1220 NECP_PARSED_PARAMETERS_FIELD_PREFERRED_AGENT_TYPE)
1223 necp_ifnet_matches_type(struct ifnet
*ifp
, u_int8_t interface_type
, bool check_delegates
)
1225 struct ifnet
*check_ifp
= ifp
;
1227 if (if_functional_type(check_ifp
, TRUE
) == interface_type
) {
1230 if (!check_delegates
) {
1233 check_ifp
= check_ifp
->if_delegated
.ifp
;
1240 necp_ifnet_matches_name(struct ifnet
*ifp
, const char *interface_name
, bool check_delegates
)
1242 struct ifnet
*check_ifp
= ifp
;
1244 if (strncmp(check_ifp
->if_xname
, interface_name
, IFXNAMSIZ
) == 0) {
1247 if (!check_delegates
) {
1250 check_ifp
= check_ifp
->if_delegated
.ifp
;
1256 necp_ifnet_matches_agent(struct ifnet
*ifp
, uuid_t
*agent_uuid
, bool check_delegates
)
1258 struct ifnet
*check_ifp
= ifp
;
1260 while (check_ifp
!= NULL
) {
1261 ifnet_lock_shared(check_ifp
);
1262 if (check_ifp
->if_agentids
!= NULL
) {
1263 for (u_int32_t index
= 0; index
< check_ifp
->if_agentcount
; index
++) {
1264 if (uuid_compare(check_ifp
->if_agentids
[index
], *agent_uuid
) == 0) {
1265 ifnet_lock_done(check_ifp
);
1270 ifnet_lock_done(check_ifp
);
1272 if (!check_delegates
) {
1275 check_ifp
= check_ifp
->if_delegated
.ifp
;
1281 necp_necp_ifnet_matches_agent_type(struct ifnet
*ifp
, const char *agent_domain
, const char *agent_type
, bool check_delegates
)
1283 struct ifnet
*check_ifp
= ifp
;
1285 while (check_ifp
!= NULL
) {
1286 ifnet_lock_shared(check_ifp
);
1287 if (check_ifp
->if_agentids
!= NULL
) {
1288 for (u_int32_t index
= 0; index
< check_ifp
->if_agentcount
; index
++) {
1289 if (uuid_is_null(check_ifp
->if_agentids
[index
])) {
1293 char if_agent_domain
[NETAGENT_DOMAINSIZE
] = { 0 };
1294 char if_agent_type
[NETAGENT_TYPESIZE
] = { 0 };
1296 if (netagent_get_agent_domain_and_type(check_ifp
->if_agentids
[index
], if_agent_domain
, if_agent_type
)) {
1297 if ((strlen(agent_domain
) == 0 ||
1298 strncmp(if_agent_domain
, agent_domain
, NETAGENT_DOMAINSIZE
) == 0) &&
1299 (strlen(agent_type
) == 0 ||
1300 strncmp(if_agent_type
, agent_type
, NETAGENT_TYPESIZE
) == 0)) {
1301 ifnet_lock_done(check_ifp
);
1307 ifnet_lock_done(check_ifp
);
1309 if (!check_delegates
) {
1312 check_ifp
= check_ifp
->if_delegated
.ifp
;
1318 necp_ifnet_matches_local_address(struct ifnet
*ifp
, struct sockaddr
*sa
)
1320 struct ifaddr
*ifa
= NULL
;
1321 bool matched_local_address
= FALSE
;
1323 // Transform sa into the ifaddr form
1324 // IPv6 Scope IDs are always embedded in the ifaddr list
1325 struct sockaddr_storage address
;
1326 u_int ifscope
= IFSCOPE_NONE
;
1327 (void)sa_copy(sa
, &address
, &ifscope
);
1328 SIN(&address
)->sin_port
= 0;
1329 if (address
.ss_family
== AF_INET6
) {
1330 SIN6(&address
)->sin6_scope_id
= 0;
1333 ifa
= ifa_ifwithaddr_scoped_locked((struct sockaddr
*)&address
, ifp
->if_index
);
1334 matched_local_address
= (ifa
!= NULL
);
1337 ifaddr_release(ifa
);
1340 return (matched_local_address
);
1344 necp_ifnet_matches_parameters(struct ifnet
*ifp
,
1345 struct necp_client_parsed_parameters
*parsed_parameters
,
1346 u_int32_t
*preferred_count
)
1348 if (preferred_count
) {
1349 *preferred_count
= 0;
1352 if (parsed_parameters
->valid_fields
& NECP_PARSED_PARAMETERS_FIELD_LOCAL_ADDR
) {
1353 if (!necp_ifnet_matches_local_address(ifp
, &parsed_parameters
->local_addr
.sa
)) {
1358 if (parsed_parameters
->valid_fields
& NECP_PARSED_PARAMETERS_FIELD_REQUIRED_IFTYPE
) {
1359 for (int i
= 0; i
< NECP_MAX_PARSED_PARAMETERS
; i
++) {
1360 if (parsed_parameters
->required_interface_types
[i
] == 0) {
1364 if (!necp_ifnet_matches_type(ifp
, parsed_parameters
->required_interface_types
[i
], FALSE
)) {
1370 if (parsed_parameters
->valid_fields
& NECP_PARSED_PARAMETERS_FIELD_PROHIBITED_IFTYPE
) {
1371 for (int i
= 0; i
< NECP_MAX_PARSED_PARAMETERS
; i
++) {
1372 if (parsed_parameters
->prohibited_interface_types
[i
] == 0) {
1376 if (necp_ifnet_matches_type(ifp
, parsed_parameters
->prohibited_interface_types
[i
], TRUE
)) {
1382 if (parsed_parameters
->valid_fields
& NECP_PARSED_PARAMETERS_FIELD_PROHIBITED_IF
) {
1383 for (int i
= 0; i
< NECP_MAX_PARSED_PARAMETERS
; i
++) {
1384 if (strlen(parsed_parameters
->prohibited_interfaces
[i
]) == 0) {
1388 if (necp_ifnet_matches_name(ifp
, parsed_parameters
->prohibited_interfaces
[i
], TRUE
)) {
1394 if (parsed_parameters
->valid_fields
& NECP_PARSED_PARAMETERS_FIELD_REQUIRED_AGENT
) {
1395 for (int i
= 0; i
< NECP_MAX_PARSED_PARAMETERS
; i
++) {
1396 if (uuid_is_null(parsed_parameters
->required_netagents
[i
])) {
1400 if (!necp_ifnet_matches_agent(ifp
, &parsed_parameters
->required_netagents
[i
], FALSE
)) {
1406 if (parsed_parameters
->valid_fields
& NECP_PARSED_PARAMETERS_FIELD_PROHIBITED_AGENT
) {
1407 for (int i
= 0; i
< NECP_MAX_PARSED_PARAMETERS
; i
++) {
1408 if (uuid_is_null(parsed_parameters
->prohibited_netagents
[i
])) {
1412 if (necp_ifnet_matches_agent(ifp
, &parsed_parameters
->prohibited_netagents
[i
], TRUE
)) {
1418 if (parsed_parameters
->valid_fields
& NECP_PARSED_PARAMETERS_FIELD_REQUIRED_AGENT_TYPE
) {
1419 for (int i
= 0; i
< NECP_MAX_PARSED_PARAMETERS
; i
++) {
1420 if (strlen(parsed_parameters
->required_netagent_types
[i
].netagent_domain
) == 0 &&
1421 strlen(parsed_parameters
->required_netagent_types
[i
].netagent_type
) == 0) {
1425 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
)) {
1431 if (parsed_parameters
->valid_fields
& NECP_PARSED_PARAMETERS_FIELD_PROHIBITED_AGENT_TYPE
) {
1432 for (int i
= 0; i
< NECP_MAX_PARSED_PARAMETERS
; i
++) {
1433 if (strlen(parsed_parameters
->prohibited_netagent_types
[i
].netagent_domain
) == 0 &&
1434 strlen(parsed_parameters
->prohibited_netagent_types
[i
].netagent_type
) == 0) {
1438 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
)) {
1444 // Checked preferred properties
1445 if (preferred_count
) {
1446 if (parsed_parameters
->valid_fields
& NECP_PARSED_PARAMETERS_FIELD_PREFERRED_AGENT
) {
1447 for (int i
= 0; i
< NECP_MAX_PARSED_PARAMETERS
; i
++) {
1448 if (uuid_is_null(parsed_parameters
->preferred_netagents
[i
])) {
1452 if (necp_ifnet_matches_agent(ifp
, &parsed_parameters
->preferred_netagents
[i
], TRUE
)) {
1453 (*preferred_count
)++;
1458 if (parsed_parameters
->valid_fields
& NECP_PARSED_PARAMETERS_FIELD_PREFERRED_AGENT_TYPE
) {
1459 for (int i
= 0; i
< NECP_MAX_PARSED_PARAMETERS
; i
++) {
1460 if (strlen(parsed_parameters
->preferred_netagent_types
[i
].netagent_domain
) == 0 &&
1461 strlen(parsed_parameters
->preferred_netagent_types
[i
].netagent_type
) == 0) {
1465 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
)) {
1466 (*preferred_count
)++;
1476 necp_find_matching_interface_index(struct necp_client_parsed_parameters
*parsed_parameters
, u_int
*return_ifindex
)
1478 struct ifnet
*ifp
= NULL
;
1479 u_int32_t best_preferred_count
= 0;
1480 bool has_preferred_fields
= FALSE
;
1481 *return_ifindex
= 0;
1483 if (parsed_parameters
->required_interface_index
!= 0) {
1484 *return_ifindex
= parsed_parameters
->required_interface_index
;
1488 if (!(parsed_parameters
->valid_fields
& NECP_PARSED_PARAMETERS_INTERESTING_IFNET_FIELDS
)) {
1492 has_preferred_fields
= (parsed_parameters
->valid_fields
& NECP_PARSED_PARAMETERS_PREFERRED_IFNET_FIELDS
);
1494 // We have interesting parameters to parse and find a matching interface
1495 ifnet_head_lock_shared();
1497 if (!(parsed_parameters
->valid_fields
& NECP_PARSED_PARAMETERS_SCOPED_IFNET_FIELDS
)) {
1498 // We do have fields to match, but they are only prohibitory
1499 // If the first interface in the list matches, we don't need to scope
1500 ifp
= TAILQ_FIRST(&ifnet_ordered_head
);
1501 if (ifp
&& necp_ifnet_matches_parameters(ifp
, parsed_parameters
, NULL
)) {
1502 // Don't set return_ifindex, so the client doesn't need to scope
1508 // First check the ordered interface list
1509 TAILQ_FOREACH(ifp
, &ifnet_ordered_head
, if_ordered_link
) {
1510 u_int32_t preferred_count
= 0;
1511 if (necp_ifnet_matches_parameters(ifp
, parsed_parameters
, &preferred_count
)) {
1512 if (preferred_count
> best_preferred_count
||
1513 *return_ifindex
== 0) {
1515 // Everything matched, and is most preferred. Return this interface.
1516 *return_ifindex
= ifp
->if_index
;
1517 best_preferred_count
= preferred_count
;
1519 if (!has_preferred_fields
) {
1526 // Then check the remaining interfaces
1527 if ((parsed_parameters
->valid_fields
& NECP_PARSED_PARAMETERS_SCOPED_IFNET_FIELDS
) &&
1528 !(parsed_parameters
->valid_fields
& NECP_PARSED_PARAMETERS_FIELD_REQUIRED_IFTYPE
) &&
1529 *return_ifindex
== 0) {
1530 TAILQ_FOREACH(ifp
, &ifnet_head
, if_link
) {
1531 u_int32_t preferred_count
= 0;
1532 if (ifp
->if_ordered_link
.tqe_next
!= NULL
||
1533 ifp
->if_ordered_link
.tqe_prev
!= NULL
) {
1534 // This interface was in the ordered list, skip
1537 if (necp_ifnet_matches_parameters(ifp
, parsed_parameters
, &preferred_count
)) {
1538 if (preferred_count
> best_preferred_count
||
1539 *return_ifindex
== 0) {
1541 // Everything matched, and is most preferred. Return this interface.
1542 *return_ifindex
= ifp
->if_index
;
1543 best_preferred_count
= preferred_count
;
1545 if (!has_preferred_fields
) {
1555 if ((parsed_parameters
->valid_fields
== (parsed_parameters
->valid_fields
& NECP_PARSED_PARAMETERS_PREFERRED_IFNET_FIELDS
)) &&
1556 best_preferred_count
== 0) {
1557 // If only has preferred fields, and nothing was found, clear the interface index and return TRUE
1558 *return_ifindex
= 0;
1562 return (*return_ifindex
!= 0);
1566 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
)
1569 u_int8_t
*parameters
;
1570 u_int32_t parameters_size
;
1572 parameters
= client
->parameters
;
1573 parameters_size
= (u_int32_t
)client
->parameters_length
;
1575 while ((offset
+ sizeof(u_int8_t
) + sizeof(u_int32_t
)) <= parameters_size
) {
1576 u_int8_t type
= necp_buffer_get_tlv_type(parameters
, offset
);
1577 u_int32_t length
= necp_buffer_get_tlv_length(parameters
, offset
);
1579 if (length
> 0 && (offset
+ sizeof(u_int8_t
) + sizeof(u_int32_t
) + length
) <= parameters_size
) {
1580 u_int8_t
*value
= necp_buffer_get_tlv_value(parameters
, offset
, NULL
);
1581 if (value
!= NULL
) {
1583 case NECP_CLIENT_PARAMETER_REAL_APPLICATION
: {
1584 if (length
>= sizeof(uuid_t
)) {
1585 uuid_copy(euuid
, value
);
1589 case NECP_CLIENT_PARAMETER_TRAFFIC_CLASS
: {
1590 if (length
>= sizeof(u_int32_t
)) {
1591 memcpy(traffic_class
, value
, sizeof(u_int32_t
));
1595 case NECP_CLIENT_PARAMETER_BOUND_INTERFACE
: {
1596 if (length
<= IFXNAMSIZ
&& length
> 0) {
1597 ifnet_t bound_interface
= NULL
;
1598 char interface_name
[IFXNAMSIZ
];
1599 memcpy(interface_name
, value
, length
);
1600 interface_name
[length
- 1] = 0; // Make sure the string is NULL terminated
1601 if (ifnet_find_by_name(interface_name
, &bound_interface
) == 0) {
1602 *ifindex
= bound_interface
->if_index
;
1603 ifnet_release(bound_interface
);
1608 case NECP_CLIENT_PARAMETER_LOCAL_ADDRESS
: {
1609 if (length
>= sizeof(struct necp_policy_condition_addr
)) {
1610 struct necp_policy_condition_addr
*address_struct
= (struct necp_policy_condition_addr
*)(void *)value
;
1611 memcpy(local
, &address_struct
->address
, sizeof(address_struct
->address
));
1615 case NECP_CLIENT_PARAMETER_REMOTE_ADDRESS
: {
1616 if (length
>= sizeof(struct necp_policy_condition_addr
)) {
1617 struct necp_policy_condition_addr
*address_struct
= (struct necp_policy_condition_addr
*)(void *)value
;
1618 memcpy(remote
, &address_struct
->address
, sizeof(address_struct
->address
));
1628 offset
+= sizeof(u_int8_t
) + sizeof(u_int32_t
) + length
;
1633 necp_fillout_current_process_details(u_int32_t
*pid
, u_int64_t
*upid
, unsigned char *uuid
, char *pname
, size_t len
)
1635 *pid
= proc_selfpid();
1636 *upid
= proc_uniqueid(current_proc());
1637 proc_selfname(pname
, (int) len
);
1638 proc_getexecutableuuid(current_proc(), uuid
, sizeof(uuid_t
));
1641 // Called from NetworkStatistics when it wishes to collect latest information for a TCP flow.
1642 // It is a responsibility of NetworkStatistics to have previously zeroed any supplied memory.
1644 necp_request_tcp_netstats(userland_stats_provider_context
*ctx
,
1645 nstat_counts
*countsp
,
1652 struct necp_client
*client
= (struct necp_client
*)ctx
;
1653 struct necp_tcp_stats
*tcpstats
= (struct necp_tcp_stats
*)client
->stats_area
;
1654 if (tcpstats
== NULL
) {
1659 *countsp
= *((struct nstat_counts
*)&tcpstats
->necp_tcp_counts
);
1663 nstat_tcp_descriptor
*desc
= (nstat_tcp_descriptor
*)metadatap
;
1665 // Metadata for the process
1666 necp_fillout_current_process_details(&desc
->pid
, &desc
->upid
, desc
->uuid
, desc
->pname
, sizeof(desc
->pname
));
1668 // Metadata that the necp client should have in TLV format.
1669 necp_find_netstat_data(client
, (union necp_sockaddr_union
*)&desc
->local
, (union necp_sockaddr_union
*)&desc
->remote
, &desc
->ifindex
, desc
->euuid
, &desc
->traffic_class
);
1672 desc
->rcvbufsize
= tcpstats
->necp_tcp_basic
.rcvbufsize
;
1673 desc
->rcvbufused
= tcpstats
->necp_tcp_basic
.rcvbufused
;
1674 desc
->eupid
= tcpstats
->necp_tcp_basic
.eupid
;
1675 desc
->epid
= tcpstats
->necp_tcp_basic
.epid
;
1676 memcpy(desc
->vuuid
, tcpstats
->necp_tcp_basic
.vuuid
, sizeof(desc
->vuuid
));
1677 desc
->ifnet_properties
= tcpstats
->necp_tcp_basic
.ifnet_properties
;
1679 // Additional TCP specific data
1680 desc
->sndbufsize
= tcpstats
->necp_tcp_extra
.sndbufsize
;
1681 desc
->sndbufused
= tcpstats
->necp_tcp_extra
.sndbufused
;
1682 desc
->txunacked
= tcpstats
->necp_tcp_extra
.txunacked
;
1683 desc
->txwindow
= tcpstats
->necp_tcp_extra
.txwindow
;
1684 desc
->txcwindow
= tcpstats
->necp_tcp_extra
.txcwindow
;
1685 desc
->traffic_mgt_flags
= tcpstats
->necp_tcp_extra
.traffic_mgt_flags
;
1687 if (tcpstats
->necp_tcp_extra
.cc_alg_index
< TCP_CC_ALGO_COUNT
) {
1688 strlcpy(desc
->cc_algo
, tcp_cc_algo_list
[tcpstats
->necp_tcp_extra
.cc_alg_index
]->name
, sizeof(desc
->cc_algo
));
1690 strlcpy(desc
->cc_algo
, "unknown", sizeof(desc
->cc_algo
));
1693 desc
->connstatus
.write_probe_failed
= tcpstats
->necp_tcp_extra
.probestatus
.write_probe_failed
;
1694 desc
->connstatus
.read_probe_failed
= tcpstats
->necp_tcp_extra
.probestatus
.read_probe_failed
;
1695 desc
->connstatus
.conn_probe_failed
= tcpstats
->necp_tcp_extra
.probestatus
.conn_probe_failed
;
1700 // Called from NetworkStatistics when it wishes to collect latest information for a UDP flow.
1702 necp_request_udp_netstats(userland_stats_provider_context
*ctx
,
1703 nstat_counts
*countsp
,
1710 struct necp_client
*client
= (struct necp_client
*)ctx
;
1711 struct necp_udp_stats
*udpstats
= (struct necp_udp_stats
*)client
->stats_area
;
1712 if (udpstats
== NULL
) {
1717 *countsp
= *((struct nstat_counts
*)&udpstats
->necp_udp_counts
);
1721 nstat_udp_descriptor
*desc
= (nstat_udp_descriptor
*)metadatap
;
1723 // Metadata for the process
1724 necp_fillout_current_process_details(&desc
->pid
, &desc
->upid
, desc
->uuid
, desc
->pname
, sizeof(desc
->pname
));
1726 // Metadata that the necp client should have in TLV format.
1727 necp_find_netstat_data(client
, (union necp_sockaddr_union
*)&desc
->local
, (union necp_sockaddr_union
*)&desc
->remote
, &desc
->ifindex
, desc
->euuid
, &desc
->traffic_class
);
1729 // Basic metadata is all that is required for UDP
1730 desc
->rcvbufsize
= udpstats
->necp_udp_basic
.rcvbufsize
;
1731 desc
->rcvbufused
= udpstats
->necp_udp_basic
.rcvbufused
;
1732 desc
->eupid
= udpstats
->necp_udp_basic
.eupid
;
1733 desc
->epid
= udpstats
->necp_udp_basic
.epid
;
1734 memcpy(desc
->vuuid
, udpstats
->necp_udp_basic
.vuuid
, sizeof(desc
->euuid
));
1735 desc
->ifnet_properties
= udpstats
->necp_udp_basic
.ifnet_properties
;
1741 necp_skywalk_priv_check_cred(proc_t p
, kauth_cred_t cred
)
1743 #pragma unused(p, cred)
1750 necp_open(struct proc
*p
, struct necp_open_args
*uap
, int *retval
)
1752 #pragma unused(retval)
1754 struct necp_fd_data
*fd_data
= NULL
;
1755 struct fileproc
*fp
= NULL
;
1758 if (uap
->flags
& NECP_OPEN_FLAG_OBSERVER
) {
1759 if (necp_skywalk_priv_check_cred(p
, kauth_cred_get()) != 0 &&
1760 priv_check_cred(kauth_cred_get(), PRIV_NET_PRIVILEGED_NETWORK_STATISTICS
, 0) != 0) {
1761 NECPLOG0(LOG_ERR
, "Client does not hold necessary entitlement to observe other NECP clients");
1767 error
= falloc(p
, &fp
, &fd
, vfs_context_current());
1772 if ((fd_data
= _MALLOC(sizeof(struct necp_fd_data
), M_NECP
,
1773 M_WAITOK
| M_ZERO
)) == NULL
) {
1778 fd_data
->flags
= uap
->flags
;
1779 LIST_INIT(&fd_data
->clients
);
1780 lck_mtx_init(&fd_data
->fd_lock
, necp_fd_mtx_grp
, necp_fd_mtx_attr
);
1781 klist_init(&fd_data
->si
.si_note
);
1782 fd_data
->proc_pid
= proc_pid(p
);
1784 fp
->f_fglob
->fg_flag
= FREAD
;
1785 fp
->f_fglob
->fg_ops
= &necp_fd_ops
;
1786 fp
->f_fglob
->fg_data
= fd_data
;
1790 *fdflags(p
, fd
) |= (UF_EXCLOSE
| UF_FORKCLOSE
);
1791 procfdtbl_releasefd(p
, fd
, NULL
);
1792 fp_drop(p
, fd
, fp
, 1);
1797 lck_rw_lock_exclusive(&necp_fd_lock
);
1798 LIST_INSERT_HEAD(&necp_fd_list
, fd_data
, chain
);
1799 lck_rw_done(&necp_fd_lock
);
1807 if (fd_data
!= NULL
) {
1808 FREE(fd_data
, M_NECP
);
1817 necp_client_add(struct necp_fd_data
*fd_data
, struct necp_client_action_args
*uap
, int *retval
)
1820 struct necp_client
*client
= NULL
;
1822 if (uap
->client_id
== 0 || uap
->client_id_len
!= sizeof(uuid_t
) ||
1823 uap
->buffer_size
== 0 || uap
->buffer_size
> NECP_MAX_CLIENT_PARAMETERS_SIZE
|| uap
->buffer
== 0) {
1828 if ((client
= _MALLOC(sizeof(struct necp_client
) + uap
->buffer_size
, M_NECP
,
1829 M_WAITOK
| M_ZERO
)) == NULL
) {
1834 error
= copyin(uap
->buffer
, client
->parameters
, uap
->buffer_size
);
1836 NECPLOG(LOG_ERR
, "necp_client_add parameters copyin error (%d)", error
);
1840 client
->parameters_length
= uap
->buffer_size
;
1842 uuid_generate_random(client
->client_id
);
1843 LIST_INIT(&client
->assertion_list
);
1845 error
= copyout(client
->client_id
, uap
->client_id
, sizeof(uuid_t
));
1847 NECPLOG(LOG_ERR
, "necp_client_add client_id copyout error (%d)", error
);
1851 lck_mtx_lock(&fd_data
->fd_lock
);
1852 LIST_INSERT_HEAD(&fd_data
->clients
, client
, chain
);
1854 // Prime the client result
1855 (void)necp_update_client_result(current_proc(), client
);
1856 lck_mtx_unlock(&fd_data
->fd_lock
);
1859 if (client
!= NULL
) {
1860 FREE(client
, M_NECP
);
1870 necp_client_remove(struct necp_fd_data
*fd_data
, struct necp_client_action_args
*uap
, int *retval
)
1873 struct necp_client
*client
= NULL
;
1874 struct necp_client
*temp_client
= NULL
;
1877 if (uap
->client_id
== 0 || uap
->client_id_len
!= sizeof(uuid_t
)) {
1882 error
= copyin(uap
->client_id
, client_id
, sizeof(uuid_t
));
1884 NECPLOG(LOG_ERR
, "necp_client_remove copyin client_id error (%d)", error
);
1888 lck_mtx_lock(&fd_data
->fd_lock
);
1889 LIST_FOREACH_SAFE(client
, &fd_data
->clients
, chain
, temp_client
) {
1890 if (uuid_compare(client
->client_id
, client_id
) == 0) {
1891 necp_destroy_client(client
);
1894 lck_mtx_unlock(&fd_data
->fd_lock
);
1902 necp_client_copy_internal(struct necp_client
*client
, bool client_is_observed
, struct necp_client_action_args
*uap
, int *retval
)
1906 if (uap
->action
== NECP_CLIENT_ACTION_COPY_PARAMETERS
) {
1907 if (uap
->buffer_size
< client
->parameters_length
) {
1911 error
= copyout(client
->parameters
, uap
->buffer
, client
->parameters_length
);
1913 NECPLOG(LOG_ERR
, "necp_client_copy parameters copyout error (%d)", error
);
1916 *retval
= client
->parameters_length
;
1917 } else if (uap
->action
== NECP_CLIENT_ACTION_COPY_RESULT
) {
1918 if (uap
->buffer_size
< (client
->result_length
+ client
->assigned_results_length
)) {
1922 error
= copyout(client
->result
, uap
->buffer
, client
->result_length
);
1924 NECPLOG(LOG_ERR
, "necp_client_copy result copyout error (%d)", error
);
1927 if (client
->assigned_results_length
&& client
->assigned_results
) {
1928 error
= copyout(client
->assigned_results
, uap
->buffer
+ client
->result_length
, client
->assigned_results_length
);
1930 NECPLOG(LOG_ERR
, "necp_client_copy assigned results copyout error (%d)", error
);
1933 *retval
= client
->result_length
+ client
->assigned_results_length
;
1935 *retval
= client
->result_length
;
1938 if (!client_is_observed
) {
1939 client
->result_read
= TRUE
;
1940 client
->assigned_result_read
= TRUE
;
1949 necp_client_copy(struct necp_fd_data
*fd_data
, struct necp_client_action_args
*uap
, int *retval
)
1952 struct necp_client
*find_client
= NULL
;
1953 struct necp_client
*client
= NULL
;
1955 uuid_clear(client_id
);
1959 if (uap
->buffer_size
== 0 || uap
->buffer
== 0) {
1964 if (uap
->action
!= NECP_CLIENT_ACTION_COPY_PARAMETERS
&&
1965 uap
->action
!= NECP_CLIENT_ACTION_COPY_RESULT
) {
1970 if (uap
->client_id
) {
1971 if (uap
->client_id_len
!= sizeof(uuid_t
)) {
1972 NECPLOG(LOG_ERR
, "Incorrect length (got %d, expected %d)", uap
->client_id_len
, sizeof(uuid_t
));
1977 error
= copyin(uap
->client_id
, client_id
, sizeof(uuid_t
));
1979 NECPLOG(LOG_ERR
, "necp_client_copy client_id copyin error (%d)", error
);
1984 lck_mtx_lock(&fd_data
->fd_lock
);
1985 LIST_FOREACH(find_client
, &fd_data
->clients
, chain
) {
1986 if (uap
->action
== NECP_CLIENT_ACTION_COPY_RESULT
&&
1987 uuid_is_null(client_id
)) {
1988 if (!find_client
->result_read
|| !find_client
->assigned_result_read
) {
1989 client
= find_client
;
1992 } else if (uuid_compare(find_client
->client_id
, client_id
) == 0) {
1993 client
= find_client
;
1998 if (client
!= NULL
) {
1999 error
= necp_client_copy_internal(client
, FALSE
, uap
, retval
);
2002 // Unlock our own client before moving on or returning
2003 lck_mtx_unlock(&fd_data
->fd_lock
);
2005 if (client
== NULL
) {
2006 if (fd_data
->flags
& NECP_OPEN_FLAG_OBSERVER
) {
2007 // Observers are allowed to lookup clients on other fds
2010 lck_rw_lock_shared(&necp_fd_lock
);
2011 struct necp_fd_data
*client_fd
= NULL
;
2012 LIST_FOREACH(client_fd
, &necp_fd_list
, chain
) {
2014 lck_mtx_lock(&client_fd
->fd_lock
);
2016 LIST_FOREACH(find_client
, &client_fd
->clients
, chain
) {
2017 if (uuid_compare(find_client
->client_id
, client_id
) == 0) {
2018 client
= find_client
;
2023 if (client
!= NULL
) {
2024 // Matched, copy out data
2025 error
= necp_client_copy_internal(client
, TRUE
, uap
, retval
);
2029 lck_mtx_unlock(&client_fd
->fd_lock
);
2031 if (client
!= NULL
) {
2037 lck_rw_done(&necp_fd_lock
);
2039 // No client found, fail
2040 if (client
== NULL
) {
2045 // No client found, and not allowed to search other fds, fail
2056 necp_client_list(struct necp_fd_data
*fd_data
, struct necp_client_action_args
*uap
, int *retval
)
2059 struct necp_client
*find_client
= NULL
;
2060 uuid_t
*list
= NULL
;
2061 u_int32_t requested_client_count
= 0;
2062 u_int32_t client_count
= 0;
2064 if (uap
->buffer_size
< sizeof(requested_client_count
) || uap
->buffer
== 0) {
2069 if (!(fd_data
->flags
& NECP_OPEN_FLAG_OBSERVER
)) {
2070 NECPLOG0(LOG_ERR
, "Client does not hold necessary entitlement to list other NECP clients");
2075 error
= copyin(uap
->buffer
, &requested_client_count
, sizeof(requested_client_count
));
2080 if (uap
->buffer_size
!= (sizeof(requested_client_count
) + requested_client_count
* sizeof(uuid_t
))) {
2085 if (requested_client_count
> 0) {
2086 if ((list
= _MALLOC(requested_client_count
* sizeof(uuid_t
), M_NECP
, M_WAITOK
| M_ZERO
)) == NULL
) {
2093 lck_rw_lock_shared(&necp_fd_lock
);
2094 struct necp_fd_data
*client_fd
= NULL
;
2095 LIST_FOREACH(client_fd
, &necp_fd_list
, chain
) {
2097 lck_mtx_lock(&client_fd
->fd_lock
);
2099 LIST_FOREACH(find_client
, &client_fd
->clients
, chain
) {
2100 if (!uuid_is_null(find_client
->client_id
)) {
2101 if (client_count
< requested_client_count
) {
2102 uuid_copy(list
[client_count
], find_client
->client_id
);
2107 lck_mtx_unlock(&client_fd
->fd_lock
);
2111 lck_rw_done(&necp_fd_lock
);
2113 error
= copyout(&client_count
, uap
->buffer
, sizeof(client_count
));
2115 NECPLOG(LOG_ERR
, "necp_client_list buffer copyout error (%d)", error
);
2119 if (requested_client_count
> 0 &&
2122 error
= copyout(list
, uap
->buffer
+ sizeof(client_count
), requested_client_count
* sizeof(uuid_t
));
2124 NECPLOG(LOG_ERR
, "necp_client_list client count copyout error (%d)", error
);
2138 necp_client_request_nexus(struct necp_fd_data
*fd_data
, struct necp_client_action_args
*uap
, int *retval
)
2141 struct necp_client
*client
= NULL
;
2143 bool requested_nexus
= FALSE
;
2145 if (uap
->client_id
== 0 || uap
->client_id_len
!= sizeof(uuid_t
)) {
2150 error
= copyin(uap
->client_id
, client_id
, sizeof(uuid_t
));
2152 NECPLOG(LOG_ERR
, "necp_client_request_nexus copyin client_id error (%d)", error
);
2156 lck_mtx_lock(&fd_data
->fd_lock
);
2157 LIST_FOREACH(client
, &fd_data
->clients
, chain
) {
2158 if (uuid_compare(client
->client_id
, client_id
) == 0) {
2159 // Request from nexus agent
2160 if (!uuid_is_null(client
->nexus_agent
)) {
2161 error
= netagent_client_message(client
->nexus_agent
, client
->client_id
,
2162 NETAGENT_MESSAGE_TYPE_REQUEST_NEXUS
);
2164 requested_nexus
= TRUE
;
2170 lck_mtx_unlock(&fd_data
->fd_lock
);
2172 if (!requested_nexus
&&
2183 necp_client_add_assertion(struct necp_client
*client
, uuid_t netagent_uuid
)
2185 struct necp_client_assertion
*new_assertion
= NULL
;
2187 MALLOC(new_assertion
, struct necp_client_assertion
*, sizeof(*new_assertion
), M_NECP
, M_WAITOK
);
2188 if (new_assertion
== NULL
) {
2189 NECPLOG0(LOG_ERR
, "Failed to allocate assertion");
2193 uuid_copy(new_assertion
->asserted_netagent
, netagent_uuid
);
2195 LIST_INSERT_HEAD(&client
->assertion_list
, new_assertion
, assertion_chain
);
2199 necp_client_remove_assertion(struct necp_client
*client
, uuid_t netagent_uuid
)
2201 struct necp_client_assertion
*found_assertion
= NULL
;
2202 struct necp_client_assertion
*search_assertion
= NULL
;
2203 LIST_FOREACH(search_assertion
, &client
->assertion_list
, assertion_chain
) {
2204 if (uuid_compare(search_assertion
->asserted_netagent
, netagent_uuid
) == 0) {
2205 found_assertion
= search_assertion
;
2210 if (found_assertion
== NULL
) {
2211 NECPLOG0(LOG_ERR
, "Netagent uuid not previously asserted");
2215 LIST_REMOVE(found_assertion
, assertion_chain
);
2216 FREE(found_assertion
, M_NECP
);
2221 necp_client_agent_action(struct necp_fd_data
*fd_data
, struct necp_client_action_args
*uap
, int *retval
)
2224 struct necp_client
*matched_client
= NULL
;
2225 struct necp_client
*client
= NULL
;
2227 bool acted_on_agent
= FALSE
;
2228 u_int8_t
*parameters
= NULL
;
2229 size_t parameters_size
= uap
->buffer_size
;
2231 if (uap
->client_id
== 0 || uap
->client_id_len
!= sizeof(uuid_t
) ||
2232 uap
->buffer_size
== 0 || uap
->buffer
== 0) {
2237 error
= copyin(uap
->client_id
, client_id
, sizeof(uuid_t
));
2239 NECPLOG(LOG_ERR
, "necp_client_agent_action copyin client_id error (%d)", error
);
2243 if ((parameters
= _MALLOC(uap
->buffer_size
, M_NECP
, M_WAITOK
| M_ZERO
)) == NULL
) {
2248 error
= copyin(uap
->buffer
, parameters
, uap
->buffer_size
);
2250 NECPLOG(LOG_ERR
, "necp_client_agent_action parameters copyin error (%d)", error
);
2254 lck_mtx_lock(&fd_data
->fd_lock
);
2255 LIST_FOREACH(client
, &fd_data
->clients
, chain
) {
2256 if (uuid_compare(client
->client_id
, client_id
) == 0) {
2257 matched_client
= client
;
2261 if (matched_client
) {
2263 while ((offset
+ sizeof(u_int8_t
) + sizeof(u_int32_t
)) <= parameters_size
) {
2264 u_int8_t type
= necp_buffer_get_tlv_type(parameters
, offset
);
2265 u_int32_t length
= necp_buffer_get_tlv_length(parameters
, offset
);
2267 if (length
> 0 && (offset
+ sizeof(u_int8_t
) + sizeof(u_int32_t
) + length
) <= parameters_size
) {
2268 u_int8_t
*value
= necp_buffer_get_tlv_value(parameters
, offset
, NULL
);
2269 if (length
>= sizeof(uuid_t
) &&
2271 (type
== NECP_CLIENT_PARAMETER_TRIGGER_AGENT
||
2272 type
== NECP_CLIENT_PARAMETER_ASSERT_AGENT
||
2273 type
== NECP_CLIENT_PARAMETER_UNASSERT_AGENT
)) {
2276 uuid_copy(agent_uuid
, value
);
2277 u_int8_t netagent_message_type
= 0;
2278 if (type
== NECP_CLIENT_PARAMETER_TRIGGER_AGENT
) {
2279 netagent_message_type
= NETAGENT_MESSAGE_TYPE_CLIENT_TRIGGER
;
2280 } else if (type
== NECP_CLIENT_PARAMETER_ASSERT_AGENT
) {
2281 netagent_message_type
= NETAGENT_MESSAGE_TYPE_CLIENT_ASSERT
;
2282 } else if (type
== NECP_CLIENT_PARAMETER_UNASSERT_AGENT
) {
2283 netagent_message_type
= NETAGENT_MESSAGE_TYPE_CLIENT_UNASSERT
;
2286 // Before unasserting, verify that the assertion was already taken
2287 if (type
== NECP_CLIENT_PARAMETER_UNASSERT_AGENT
) {
2288 if (!necp_client_remove_assertion(client
, agent_uuid
)) {
2294 error
= netagent_client_message(agent_uuid
, client_id
,
2295 netagent_message_type
);
2297 acted_on_agent
= TRUE
;
2302 // Only save the assertion if the action succeeded
2303 if (type
== NECP_CLIENT_PARAMETER_ASSERT_AGENT
) {
2304 necp_client_add_assertion(client
, agent_uuid
);
2309 offset
+= sizeof(u_int8_t
) + sizeof(u_int32_t
) + length
;
2312 lck_mtx_unlock(&fd_data
->fd_lock
);
2314 if (!acted_on_agent
&&
2320 if (parameters
!= NULL
) {
2321 FREE(parameters
, M_NECP
);
2329 necp_client_copy_agent(__unused
struct necp_fd_data
*fd_data
, struct necp_client_action_args
*uap
, int *retval
)
2334 if (uap
->client_id
== 0 || uap
->client_id_len
!= sizeof(uuid_t
) ||
2335 uap
->buffer_size
== 0 || uap
->buffer
== 0) {
2336 NECPLOG0(LOG_ERR
, "necp_client_copy_agent bad input");
2341 error
= copyin(uap
->client_id
, agent_uuid
, sizeof(uuid_t
));
2343 NECPLOG(LOG_ERR
, "necp_client_copy_agent copyin agent_uuid error (%d)", error
);
2347 error
= netagent_copyout(agent_uuid
, uap
->buffer
, uap
->buffer_size
);
2349 NECPLOG(LOG_ERR
, "necp_client_copy_agent netagent_copyout error (%d)", error
);
2359 necp_client_copy_interface(__unused
struct necp_fd_data
*fd_data
, struct necp_client_action_args
*uap
, int *retval
)
2362 u_int32_t interface_index
= 0;
2363 struct necp_interface_details interface_details
;
2365 if (uap
->client_id
== 0 || uap
->client_id_len
!= sizeof(u_int32_t
) ||
2366 uap
->buffer_size
< sizeof(interface_details
) || uap
->buffer
== 0) {
2367 NECPLOG0(LOG_ERR
, "necp_client_copy_interface bad input");
2372 error
= copyin(uap
->client_id
, &interface_index
, sizeof(u_int32_t
));
2374 NECPLOG(LOG_ERR
, "necp_client_copy_interface copyin interface_index error (%d)", error
);
2378 if (interface_index
== 0) {
2380 NECPLOG(LOG_ERR
, "necp_client_copy_interface bad interface_index (%d)", interface_index
);
2384 memset(&interface_details
, 0, sizeof(interface_details
));
2386 ifnet_head_lock_shared();
2387 ifnet_t interface
= NULL
;
2388 if (interface_index
!= IFSCOPE_NONE
&& (int)interface_index
<= if_index
) {
2389 interface
= ifindex2ifnet
[interface_index
];
2392 if (interface
!= NULL
) {
2393 if (interface
->if_xname
!= NULL
) {
2394 strlcpy((char *)&interface_details
.name
, interface
->if_xname
, sizeof(interface_details
.name
));
2396 interface_details
.index
= interface
->if_index
;
2397 interface_details
.generation
= ifnet_get_generation(interface
);
2398 if (interface
->if_delegated
.ifp
!= NULL
) {
2399 interface_details
.delegate_index
= interface
->if_delegated
.ifp
->if_index
;
2401 interface_details
.functional_type
= if_functional_type(interface
, TRUE
);
2402 if (IFNET_IS_EXPENSIVE(interface
)) {
2403 interface_details
.flags
|= NECP_INTERFACE_FLAG_EXPENSIVE
;
2405 interface_details
.mtu
= interface
->if_mtu
;
2407 u_int8_t ipv4_signature_len
= sizeof(interface_details
.ipv4_signature
);
2408 u_int16_t ipv4_signature_flags
;
2409 ifnet_get_netsignature(interface
, AF_INET
, &ipv4_signature_len
, &ipv4_signature_flags
,
2410 (u_int8_t
*)&interface_details
.ipv4_signature
);
2412 u_int8_t ipv6_signature_len
= sizeof(interface_details
.ipv6_signature
);
2413 u_int16_t ipv6_signature_flags
;
2414 ifnet_get_netsignature(interface
, AF_INET6
, &ipv6_signature_len
, &ipv6_signature_flags
,
2415 (u_int8_t
*)&interface_details
.ipv6_signature
);
2420 error
= copyout(&interface_details
, uap
->buffer
, sizeof(interface_details
));
2422 NECPLOG(LOG_ERR
, "necp_client_copy_interface copyout error (%d)", error
);
2432 necp_client_stats_action(struct necp_client
*client
, user_addr_t buffer
, user_size_t buffer_size
)
2435 struct necp_stats_hdr
*stats_hdr
= NULL
;
2437 if (client
->stats_area
) {
2438 // Close old stats if required.
2439 if ((client
->stats_uaddr
!= buffer
) || (client
->stats_ulen
!= buffer_size
)) {
2440 necp_destroy_client_stats(client
);
2444 if ((buffer
== 0) || (buffer_size
== 0)) {
2448 if (client
->stats_area
) {
2450 error
= copyin(client
->stats_uaddr
, client
->stats_area
, client
->stats_ulen
);
2452 NECPLOG(LOG_ERR
, "necp_client_stats_action copyin error on update (%d)", error
);
2454 // Future use - check
2455 stats_hdr
= (necp_stats_hdr
*)client
->stats_area
;
2456 if (stats_hdr
->necp_stats_event
!= 0) {
2457 ntstat_userland_stats_event(client
->stats_handler_context
, (userland_stats_event_t
)stats_hdr
->necp_stats_event
);
2464 if ((buffer_size
> sizeof(necp_all_stats
)) || (buffer_size
< sizeof(necp_stats_hdr
))) {
2469 if ((stats_hdr
= _MALLOC(buffer_size
, M_NECP
, M_WAITOK
| M_ZERO
)) == NULL
) {
2474 client
->stats_handler_context
= NULL
;
2475 client
->stats_uaddr
= buffer
;
2476 client
->stats_ulen
= buffer_size
;
2477 client
->stats_area
= stats_hdr
;
2478 error
= copyin(client
->stats_uaddr
, client
->stats_area
, client
->stats_ulen
);
2480 NECPLOG(LOG_ERR
, "necp_client_stats_action copyin error on create (%d)", error
);
2484 switch (stats_hdr
->necp_stats_type
) {
2485 case NECP_CLIENT_STATISTICS_TYPE_TCP
: {
2486 if (stats_hdr
->necp_stats_ver
== NECP_CLIENT_STATISTICS_TYPE_TCP_VER_1
) {
2487 client
->stats_handler_context
= ntstat_userland_stats_open((userland_stats_provider_context
*)client
,
2488 NSTAT_PROVIDER_TCP_USERLAND
, 0, necp_request_tcp_netstats
);
2489 if (client
->stats_handler_context
== NULL
) {
2497 case NECP_CLIENT_STATISTICS_TYPE_UDP
: {
2498 if (stats_hdr
->necp_stats_ver
!= NECP_CLIENT_STATISTICS_TYPE_UDP_VER_1
) {
2499 client
->stats_handler_context
= ntstat_userland_stats_open((userland_stats_provider_context
*)client
,
2500 NSTAT_PROVIDER_UDP_USERLAND
, 0, necp_request_udp_netstats
);
2501 if (client
->stats_handler_context
== NULL
) {
2515 if ((error
) && (stats_hdr
!= NULL
)) {
2516 FREE(stats_hdr
, M_NECP
);
2517 client
->stats_area
= NULL
;
2518 client
->stats_handler_context
= NULL
;
2519 client
->stats_uaddr
= 0;
2520 client
->stats_ulen
= 0;
2527 necp_client_set_statistics(__unused
struct necp_fd_data
*fd_data
, struct necp_client_action_args
*uap
, int *retval
)
2530 struct necp_client
*find_client
= NULL
;
2531 struct necp_client
*client
= NULL
;
2534 if (uap
->client_id
== 0 || uap
->client_id_len
!= sizeof(uuid_t
)) {
2539 error
= copyin(uap
->client_id
, client_id
, sizeof(uuid_t
));
2541 NECPLOG(LOG_ERR
, "necp_client_set_statistics copyin client_id error (%d)", error
);
2545 lck_mtx_lock(&fd_data
->fd_lock
);
2546 LIST_FOREACH(find_client
, &fd_data
->clients
, chain
) {
2547 if (uuid_compare(find_client
->client_id
, client_id
) == 0) {
2548 client
= find_client
;
2554 error
= necp_client_stats_action(client
, uap
->buffer
, uap
->buffer_size
);
2558 lck_mtx_unlock(&fd_data
->fd_lock
);
2565 necp_client_action(struct proc
*p
, struct necp_client_action_args
*uap
, int *retval
)
2569 int return_value
= 0;
2570 struct necp_fd_data
*fd_data
= NULL
;
2571 error
= necp_find_fd_data(uap
->necp_fd
, &fd_data
);
2573 NECPLOG(LOG_ERR
, "necp_client_action find fd error (%d)", error
);
2577 u_int32_t action
= uap
->action
;
2579 case NECP_CLIENT_ACTION_ADD
: {
2580 return_value
= necp_client_add(fd_data
, uap
, retval
);
2583 case NECP_CLIENT_ACTION_REMOVE
: {
2584 return_value
= necp_client_remove(fd_data
, uap
, retval
);
2587 case NECP_CLIENT_ACTION_COPY_PARAMETERS
:
2588 case NECP_CLIENT_ACTION_COPY_RESULT
: {
2589 return_value
= necp_client_copy(fd_data
, uap
, retval
);
2592 case NECP_CLIENT_ACTION_COPY_LIST
: {
2593 return_value
= necp_client_list(fd_data
, uap
, retval
);
2596 case NECP_CLIENT_ACTION_REQUEST_NEXUS_INSTANCE
: {
2597 return_value
= necp_client_request_nexus(fd_data
, uap
, retval
);
2600 case NECP_CLIENT_ACTION_AGENT
: {
2601 return_value
= necp_client_agent_action(fd_data
, uap
, retval
);
2604 case NECP_CLIENT_ACTION_COPY_AGENT
: {
2605 return_value
= necp_client_copy_agent(fd_data
, uap
, retval
);
2608 case NECP_CLIENT_ACTION_COPY_INTERFACE
: {
2609 return_value
= necp_client_copy_interface(fd_data
, uap
, retval
);
2612 case NECP_CLIENT_ACTION_SET_STATISTICS
: {
2613 return_value
= necp_client_set_statistics(fd_data
, uap
, retval
);
2617 NECPLOG(LOG_ERR
, "necp_client_action unknown action (%u)", action
);
2618 return_value
= EINVAL
;
2623 file_drop(uap
->necp_fd
);
2625 return (return_value
);
2628 #define NECP_MAX_MATCH_POLICY_PARAMETER_SIZE 1024
2631 necp_match_policy(struct proc
*p
, struct necp_match_policy_args
*uap
, int32_t *retval
)
2633 #pragma unused(retval)
2634 u_int8_t
*parameters
= NULL
;
2635 struct necp_aggregate_result returned_result
;
2643 if (uap
->parameters
== 0 || uap
->parameters_size
== 0 || uap
->parameters_size
> NECP_MAX_MATCH_POLICY_PARAMETER_SIZE
|| uap
->returned_result
== 0) {
2648 MALLOC(parameters
, u_int8_t
*, uap
->parameters_size
, M_NECP
, M_WAITOK
| M_ZERO
);
2649 if (parameters
== NULL
) {
2653 // Copy parameters in
2654 error
= copyin(uap
->parameters
, parameters
, uap
->parameters_size
);
2659 error
= necp_application_find_policy_match_internal(p
, parameters
, uap
->parameters_size
, &returned_result
, NULL
, 0);
2664 // Copy return value back
2665 error
= copyout(&returned_result
, uap
->returned_result
, sizeof(struct necp_aggregate_result
));
2670 if (parameters
!= NULL
) {
2671 FREE(parameters
, M_NECP
);
2676 /// Socket operations
2677 #define NECP_MAX_SOCKET_ATTRIBUTE_STRING_LENGTH 253
2680 necp_set_socket_attribute(u_int8_t
*buffer
, size_t buffer_length
, u_int8_t type
, char **buffer_p
)
2684 size_t string_size
= 0;
2685 char *local_string
= NULL
;
2686 u_int8_t
*value
= NULL
;
2688 cursor
= necp_buffer_find_tlv(buffer
, buffer_length
, 0, type
, 0);
2690 // This will clear out the parameter
2694 string_size
= necp_buffer_get_tlv_length(buffer
, cursor
);
2695 if (string_size
== 0 || string_size
> NECP_MAX_SOCKET_ATTRIBUTE_STRING_LENGTH
) {
2696 // This will clear out the parameter
2700 MALLOC(local_string
, char *, string_size
+ 1, M_NECP
, M_WAITOK
| M_ZERO
);
2701 if (local_string
== NULL
) {
2702 NECPLOG(LOG_ERR
, "Failed to allocate a socket attribute buffer (size %d)", string_size
);
2706 value
= necp_buffer_get_tlv_value(buffer
, cursor
, NULL
);
2707 if (value
== NULL
) {
2708 NECPLOG0(LOG_ERR
, "Failed to get socket attribute");
2712 memcpy(local_string
, value
, string_size
);
2713 local_string
[string_size
] = 0;
2716 if (*buffer_p
!= NULL
) {
2717 FREE(*buffer_p
, M_NECP
);
2721 *buffer_p
= local_string
;
2724 if (local_string
!= NULL
) {
2725 FREE(local_string
, M_NECP
);
2731 necp_set_socket_attributes(struct socket
*so
, struct sockopt
*sopt
)
2734 u_int8_t
*buffer
= NULL
;
2735 struct inpcb
*inp
= NULL
;
2737 if ((SOCK_DOM(so
) != PF_INET
2739 && SOCK_DOM(so
) != PF_INET6
2746 inp
= sotoinpcb(so
);
2748 size_t valsize
= sopt
->sopt_valsize
;
2750 valsize
> ((sizeof(u_int8_t
) + sizeof(u_int32_t
) + NECP_MAX_SOCKET_ATTRIBUTE_STRING_LENGTH
) * 2)) {
2754 MALLOC(buffer
, u_int8_t
*, valsize
, M_NECP
, M_WAITOK
| M_ZERO
);
2755 if (buffer
== NULL
) {
2759 error
= sooptcopyin(sopt
, buffer
, valsize
, 0);
2764 error
= necp_set_socket_attribute(buffer
, valsize
, NECP_TLV_ATTRIBUTE_DOMAIN
, &inp
->inp_necp_attributes
.inp_domain
);
2766 NECPLOG0(LOG_ERR
, "Could not set domain TLV for socket attributes");
2770 error
= necp_set_socket_attribute(buffer
, valsize
, NECP_TLV_ATTRIBUTE_ACCOUNT
, &inp
->inp_necp_attributes
.inp_account
);
2772 NECPLOG0(LOG_ERR
, "Could not set account TLV for socket attributes");
2777 NECPLOG(LOG_DEBUG
, "Set on socket: Domain %s, Account %s", inp
->inp_necp_attributes
.inp_domain
, inp
->inp_necp_attributes
.inp_account
);
2780 if (buffer
!= NULL
) {
2781 FREE(buffer
, M_NECP
);
2788 necp_get_socket_attributes(struct socket
*so
, struct sockopt
*sopt
)
2791 u_int8_t
*buffer
= NULL
;
2792 u_int8_t
*cursor
= NULL
;
2794 struct inpcb
*inp
= sotoinpcb(so
);
2796 if (inp
->inp_necp_attributes
.inp_domain
!= NULL
) {
2797 valsize
+= sizeof(u_int8_t
) + sizeof(u_int32_t
) + strlen(inp
->inp_necp_attributes
.inp_domain
);
2799 if (inp
->inp_necp_attributes
.inp_account
!= NULL
) {
2800 valsize
+= sizeof(u_int8_t
) + sizeof(u_int32_t
) + strlen(inp
->inp_necp_attributes
.inp_account
);
2806 MALLOC(buffer
, u_int8_t
*, valsize
, M_NECP
, M_WAITOK
| M_ZERO
);
2807 if (buffer
== NULL
) {
2812 if (inp
->inp_necp_attributes
.inp_domain
!= NULL
) {
2813 cursor
= necp_buffer_write_tlv(cursor
, NECP_TLV_ATTRIBUTE_DOMAIN
, strlen(inp
->inp_necp_attributes
.inp_domain
), inp
->inp_necp_attributes
.inp_domain
);
2816 if (inp
->inp_necp_attributes
.inp_account
!= NULL
) {
2817 cursor
= necp_buffer_write_tlv(cursor
, NECP_TLV_ATTRIBUTE_ACCOUNT
, strlen(inp
->inp_necp_attributes
.inp_account
), inp
->inp_necp_attributes
.inp_account
);
2820 error
= sooptcopyout(sopt
, buffer
, valsize
);
2825 if (buffer
!= NULL
) {
2826 FREE(buffer
, M_NECP
);
2833 necp_inpcb_dispose(struct inpcb
*inp
)
2835 if (inp
->inp_necp_attributes
.inp_domain
!= NULL
) {
2836 FREE(inp
->inp_necp_attributes
.inp_domain
, M_NECP
);
2837 inp
->inp_necp_attributes
.inp_domain
= NULL
;
2839 if (inp
->inp_necp_attributes
.inp_account
!= NULL
) {
2840 FREE(inp
->inp_necp_attributes
.inp_account
, M_NECP
);
2841 inp
->inp_necp_attributes
.inp_account
= NULL
;
2848 necp_client_init(void)
2852 necp_fd_grp_attr
= lck_grp_attr_alloc_init();
2853 if (necp_fd_grp_attr
== NULL
) {
2854 NECPLOG0(LOG_ERR
, "lck_grp_attr_alloc_init failed");
2859 necp_fd_mtx_grp
= lck_grp_alloc_init("necp_fd", necp_fd_grp_attr
);
2860 if (necp_fd_mtx_grp
== NULL
) {
2861 NECPLOG0(LOG_ERR
, "lck_grp_alloc_init failed");
2866 necp_fd_mtx_attr
= lck_attr_alloc_init();
2867 if (necp_fd_mtx_attr
== NULL
) {
2868 NECPLOG0(LOG_ERR
, "lck_attr_alloc_init failed");
2873 necp_client_tcall
= thread_call_allocate(necp_update_all_clients_callout
, NULL
);
2874 if (necp_client_tcall
== NULL
) {
2875 NECPLOG0(LOG_ERR
, "thread_call_allocate failed");
2880 lck_rw_init(&necp_fd_lock
, necp_fd_mtx_grp
, necp_fd_mtx_attr
);
2882 LIST_INIT(&necp_fd_list
);
2886 if (necp_fd_mtx_attr
!= NULL
) {
2887 lck_attr_free(necp_fd_mtx_attr
);
2888 necp_fd_mtx_attr
= NULL
;
2890 if (necp_fd_mtx_grp
!= NULL
) {
2891 lck_grp_free(necp_fd_mtx_grp
);
2892 necp_fd_mtx_grp
= NULL
;
2894 if (necp_fd_grp_attr
!= NULL
) {
2895 lck_grp_attr_free(necp_fd_grp_attr
);
2896 necp_fd_grp_attr
= NULL
;