]> git.saurik.com Git - apple/xnu.git/blame - bsd/net/necp_client.c
xnu-6153.121.1.tar.gz
[apple/xnu.git] / bsd / net / necp_client.c
CommitLineData
39037602 1/*
cb323159 2 * Copyright (c) 2015-2019 Apple Inc. All rights reserved.
39037602
A
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29#include <string.h>
5ba3f43e
A
30
31#include <kern/thread_call.h>
32#include <kern/zalloc.h>
33
39037602 34#include <libkern/OSMalloc.h>
5ba3f43e 35
39037602 36#include <net/if.h>
5ba3f43e
A
37#include <net/if_var.h>
38#include <net/net_api_stats.h>
39#include <net/necp.h>
40#include <net/network_agent.h>
41#include <net/ntstat.h>
42
43#include <netinet/in_pcb.h>
cb323159 44#include <netinet/in_var.h>
39037602
A
45#include <netinet/ip.h>
46#include <netinet/ip6.h>
5ba3f43e 47#include <netinet/mp_pcb.h>
39037602 48#include <netinet/tcp_cc.h>
5ba3f43e
A
49#include <netinet/tcp_fsm.h>
50#include <netinet/tcp_cache.h>
51#include <netinet6/in6_var.h>
52
53#include <sys/domain.h>
39037602 54#include <sys/file_internal.h>
5ba3f43e
A
55#include <sys/kauth.h>
56#include <sys/kernel.h>
57#include <sys/malloc.h>
39037602 58#include <sys/poll.h>
5ba3f43e
A
59#include <sys/priv.h>
60#include <sys/protosw.h>
61#include <sys/queue.h>
62#include <sys/socket.h>
63#include <sys/socketvar.h>
64#include <sys/sysproto.h>
65#include <sys/systm.h>
66#include <sys/types.h>
67#include <sys/codesign.h>
68#include <libkern/section_keywords.h>
69
cb323159
A
70#include <os/refcnt.h>
71
39037602
A
72
73/*
74 * NECP Client Architecture
75 * ------------------------------------------------
76 * See <net/necp.c> for a discussion on NECP database architecture.
77 *
78 * Each client of NECP provides a set of parameters for a connection or network state
79 * evaluation, on which NECP policy evaluation is run. This produces a policy result
80 * which can be accessed by the originating process, along with events for when policies
81 * results have changed.
82 *
83 * ------------------------------------------------
84 * NECP Client FD
85 * ------------------------------------------------
86 * A process opens an NECP file descriptor using necp_open(). This is a very simple
87 * file descriptor, upon which the process may do the following operations:
88 * - necp_client_action(...), to add/remove/query clients
89 * - kqueue, to watch for readable events
90 * - close(), to close the client session and release all clients
91 *
92 * Client objects are allocated structures that hang off of the file descriptor. Each
93 * client contains:
94 * - Client ID, a UUID that references the client across the system
95 * - Parameters, a buffer of TLVs that describe the client's connection parameters,
96 * such as the remote and local endpoints, interface requirements, etc.
97 * - Result, a buffer of TLVs containing the current policy evaluation for the client.
98 * This result will be updated whenever a network change occurs that impacts the
99 * policy result for that client.
100 *
101 * +--------------+
102 * | NECP fd |
103 * +--------------+
104 * ||
105 * ==================================
106 * || || ||
107 * +--------------+ +--------------+ +--------------+
108 * | Client ID | | Client ID | | Client ID |
109 * | ---- | | ---- | | ---- |
110 * | Parameters | | Parameters | | Parameters |
111 * | ---- | | ---- | | ---- |
112 * | Result | | Result | | Result |
113 * +--------------+ +--------------+ +--------------+
114 *
115 * ------------------------------------------------
116 * Client Actions
117 * ------------------------------------------------
118 * - Add. Input parameters as a buffer of TLVs, and output a client ID. Allocates a
119 * new client structure on the file descriptor.
120 * - Remove. Input a client ID. Removes a client structure from the file descriptor.
121 * - Copy Parameters. Input a client ID, and output parameter TLVs.
122 * - Copy Result. Input a client ID, and output result TLVs. Alternatively, input empty
123 * client ID and get next unread client result.
124 * - Copy List. List all client IDs.
125 *
126 * ------------------------------------------------
127 * Client Policy Evaluation
128 * ------------------------------------------------
129 * Policies are evaluated for clients upon client creation, and upon update events,
130 * which are network/agent/policy changes coalesced by a timer.
131 *
132 * The policy evaluation goes through the following steps:
133 * 1. Parse client parameters.
134 * 2. Select a scoped interface if applicable. This involves using require/prohibit
135 * parameters, along with the local address, to select the most appropriate interface
136 * if not explicitly set by the client parameters.
137 * 3. Run NECP application-level policy evalution
138 * 4. Set policy result into client result buffer.
139 *
140 * ------------------------------------------------
141 * Client Observers
142 * ------------------------------------------------
143 * If necp_open() is called with the NECP_OPEN_FLAG_OBSERVER flag, and the process
144 * passes the necessary privilege check, the fd is allowed to use necp_client_action()
145 * to copy client state attached to the file descriptors of other processes, and to
146 * list all client IDs on the system.
147 */
148
149extern u_int32_t necp_debug;
150
39037602
A
151static int necpop_select(struct fileproc *, int, void *, vfs_context_t);
152static int necpop_close(struct fileglob *, vfs_context_t);
cb323159 153static int necpop_kqfilter(struct fileproc *, struct knote *, struct kevent_qos_s *);
39037602
A
154
155// Timer functions
156static int necp_timeout_microseconds = 1000 * 100; // 100ms
157static int necp_timeout_leeway_microseconds = 1000 * 500; // 500ms
5ba3f43e
A
158
159static int necp_client_fd_count = 0;
160static int necp_observer_fd_count = 0;
161static int necp_client_count = 0;
162static int necp_socket_flow_count = 0;
163static int necp_if_flow_count = 0;
164static int necp_observer_message_limit = 256;
165
cb323159
A
166os_refgrp_decl(static, necp_client_refgrp, "NECPClientRefGroup", NULL);
167
5ba3f43e
A
168SYSCTL_INT(_net_necp, NECPCTL_CLIENT_FD_COUNT, client_fd_count, CTLFLAG_LOCKED | CTLFLAG_RD, &necp_client_fd_count, 0, "");
169SYSCTL_INT(_net_necp, NECPCTL_OBSERVER_FD_COUNT, observer_fd_count, CTLFLAG_LOCKED | CTLFLAG_RD, &necp_observer_fd_count, 0, "");
170SYSCTL_INT(_net_necp, NECPCTL_CLIENT_COUNT, client_count, CTLFLAG_LOCKED | CTLFLAG_RD, &necp_client_count, 0, "");
171SYSCTL_INT(_net_necp, NECPCTL_SOCKET_FLOW_COUNT, socket_flow_count, CTLFLAG_LOCKED | CTLFLAG_RD, &necp_socket_flow_count, 0, "");
172SYSCTL_INT(_net_necp, NECPCTL_IF_FLOW_COUNT, if_flow_count, CTLFLAG_LOCKED | CTLFLAG_RD, &necp_if_flow_count, 0, "");
173SYSCTL_INT(_net_necp, NECPCTL_OBSERVER_MESSAGE_LIMIT, observer_message_limit, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_observer_message_limit, 256, "");
174
0a7de745
A
175#define NECP_MAX_CLIENT_LIST_SIZE 1024 * 1024 // 1MB
176#define NECP_MAX_AGENT_ACTION_SIZE 256
5ba3f43e 177
39037602 178extern int tvtohz(struct timeval *);
5ba3f43e 179extern unsigned int get_maxmtu(struct rtentry *);
39037602
A
180
181// Parsed parameters
0a7de745
A
182#define NECP_PARSED_PARAMETERS_FIELD_LOCAL_ADDR 0x00001
183#define NECP_PARSED_PARAMETERS_FIELD_REMOTE_ADDR 0x00002
184#define NECP_PARSED_PARAMETERS_FIELD_REQUIRED_IF 0x00004
185#define NECP_PARSED_PARAMETERS_FIELD_PROHIBITED_IF 0x00008
186#define NECP_PARSED_PARAMETERS_FIELD_REQUIRED_IFTYPE 0x00010
187#define NECP_PARSED_PARAMETERS_FIELD_PROHIBITED_IFTYPE 0x00020
188#define NECP_PARSED_PARAMETERS_FIELD_REQUIRED_AGENT 0x00040
189#define NECP_PARSED_PARAMETERS_FIELD_PROHIBITED_AGENT 0x00080
190#define NECP_PARSED_PARAMETERS_FIELD_PREFERRED_AGENT 0x00100
191#define NECP_PARSED_PARAMETERS_FIELD_AVOIDED_AGENT 0x00200
192#define NECP_PARSED_PARAMETERS_FIELD_REQUIRED_AGENT_TYPE 0x00400
193#define NECP_PARSED_PARAMETERS_FIELD_PROHIBITED_AGENT_TYPE 0x00800
194#define NECP_PARSED_PARAMETERS_FIELD_PREFERRED_AGENT_TYPE 0x01000
195#define NECP_PARSED_PARAMETERS_FIELD_AVOIDED_AGENT_TYPE 0x02000
196#define NECP_PARSED_PARAMETERS_FIELD_FLAGS 0x04000
197#define NECP_PARSED_PARAMETERS_FIELD_IP_PROTOCOL 0x08000
198#define NECP_PARSED_PARAMETERS_FIELD_EFFECTIVE_PID 0x10000
199#define NECP_PARSED_PARAMETERS_FIELD_EFFECTIVE_UUID 0x20000
200#define NECP_PARSED_PARAMETERS_FIELD_TRAFFIC_CLASS 0x40000
201#define NECP_PARSED_PARAMETERS_FIELD_LOCAL_PORT 0x80000
cb323159
A
202#define NECP_PARSED_PARAMETERS_FIELD_DELEGATED_UPID 0x100000
203#define NECP_PARSED_PARAMETERS_FIELD_ETHERTYPE 0x200000
204#define NECP_PARSED_PARAMETERS_FIELD_TRANSPORT_PROTOCOL 0x400000
205#define NECP_PARSED_PARAMETERS_FIELD_LOCAL_ADDR_PREFERENCE 0x800000
39037602 206
cb323159
A
207
208#define NECP_MAX_INTERFACE_PARAMETERS 16
209#define NECP_MAX_AGENT_PARAMETERS 4
39037602
A
210struct necp_client_parsed_parameters {
211 u_int32_t valid_fields;
5ba3f43e 212 u_int32_t flags;
cb323159 213 u_int64_t delegated_upid;
39037602
A
214 union necp_sockaddr_union local_addr;
215 union necp_sockaddr_union remote_addr;
216 u_int32_t required_interface_index;
cb323159 217 char prohibited_interfaces[NECP_MAX_INTERFACE_PARAMETERS][IFXNAMSIZ];
5ba3f43e 218 u_int8_t required_interface_type;
cb323159
A
219 u_int8_t local_address_preference;
220 u_int8_t prohibited_interface_types[NECP_MAX_INTERFACE_PARAMETERS];
221 struct necp_client_parameter_netagent_type required_netagent_types[NECP_MAX_AGENT_PARAMETERS];
222 struct necp_client_parameter_netagent_type prohibited_netagent_types[NECP_MAX_AGENT_PARAMETERS];
223 struct necp_client_parameter_netagent_type preferred_netagent_types[NECP_MAX_AGENT_PARAMETERS];
224 struct necp_client_parameter_netagent_type avoided_netagent_types[NECP_MAX_AGENT_PARAMETERS];
225 uuid_t required_netagents[NECP_MAX_AGENT_PARAMETERS];
226 uuid_t prohibited_netagents[NECP_MAX_AGENT_PARAMETERS];
227 uuid_t preferred_netagents[NECP_MAX_AGENT_PARAMETERS];
228 uuid_t avoided_netagents[NECP_MAX_AGENT_PARAMETERS];
229 u_int8_t ip_protocol;
230 u_int8_t transport_protocol;
231 u_int16_t ethertype;
5ba3f43e
A
232 pid_t effective_pid;
233 uuid_t effective_uuid;
234 u_int32_t traffic_class;
39037602
A
235};
236
5ba3f43e
A
237static bool
238necp_find_matching_interface_index(struct necp_client_parsed_parameters *parsed_parameters,
0a7de745 239 u_int *return_ifindex, bool *validate_agents);
5ba3f43e
A
240
241static bool
242necp_ifnet_matches_local_address(struct ifnet *ifp, struct sockaddr *sa);
243
244static bool
245necp_ifnet_matches_parameters(struct ifnet *ifp,
0a7de745 246 struct necp_client_parsed_parameters *parsed_parameters,
cb323159 247 u_int32_t override_flags,
0a7de745 248 u_int32_t *preferred_count,
cb323159
A
249 bool secondary_interface,
250 bool require_scoped_field);
39037602
A
251
252static const struct fileops necp_fd_ops = {
cb323159
A
253 .fo_type = DTYPE_NETPOLICY,
254 .fo_read = fo_no_read,
255 .fo_write = fo_no_write,
256 .fo_ioctl = fo_no_ioctl,
257 .fo_select = necpop_select,
258 .fo_close = necpop_close,
259 .fo_drain = fo_no_drain,
39037602 260 .fo_kqfilter = necpop_kqfilter,
39037602
A
261};
262
263struct necp_client_assertion {
264 LIST_ENTRY(necp_client_assertion) assertion_chain;
265 uuid_t asserted_netagent;
266};
267
5ba3f43e
A
268struct necp_client_flow_header {
269 struct necp_tlv_header outer_header;
d9a64523
A
270 struct necp_tlv_header flow_id_tlv_header;
271 uuid_t flow_id;
5ba3f43e
A
272 struct necp_tlv_header flags_tlv_header;
273 u_int32_t flags_value;
274 struct necp_tlv_header interface_tlv_header;
275 struct necp_client_result_interface interface_value;
276} __attribute__((__packed__));
277
278struct necp_client_flow_protoctl_event_header {
279 struct necp_tlv_header protoctl_tlv_header;
280 struct necp_client_flow_protoctl_event protoctl_event;
281} __attribute__((__packed__));
282
283struct necp_client_nexus_flow_header {
284 struct necp_client_flow_header flow_header;
285 struct necp_tlv_header agent_tlv_header;
286 struct necp_client_result_netagent agent_value;
287 struct necp_tlv_header tfo_cookie_tlv_header;
288 u_int8_t tfo_cookie_value[NECP_TFO_COOKIE_LEN_MAX];
289} __attribute__((__packed__));
290
a39ff7e2 291
d9a64523
A
292struct necp_client_flow {
293 LIST_ENTRY(necp_client_flow) flow_chain;
294 unsigned invalid : 1;
295 unsigned nexus : 1; // If true, flow is a nexus; if false, flow is attached to socket
296 unsigned socket : 1;
297 unsigned viable : 1;
298 unsigned assigned : 1;
299 unsigned has_protoctl_event : 1;
300 unsigned check_tcp_heuristics : 1;
301 unsigned _reserved : 1;
302 union {
303 uuid_t nexus_agent;
304 struct {
305 void *socket_handle;
306 necp_client_flow_cb cb;
307 };
308 } u;
309 uint32_t interface_index;
310 uint16_t interface_flags;
311 uint32_t necp_flow_flags;
312 struct necp_client_flow_protoctl_event protoctl_event;
313 union necp_sockaddr_union local_addr;
314 union necp_sockaddr_union remote_addr;
315
316 size_t assigned_results_length;
317 u_int8_t *assigned_results;
318};
319
320struct necp_client_flow_registration {
321 RB_ENTRY(necp_client_flow_registration) fd_link;
322 RB_ENTRY(necp_client_flow_registration) global_link;
323 RB_ENTRY(necp_client_flow_registration) client_link;
324 LIST_ENTRY(necp_client_flow_registration) collect_stats_chain;
325 uuid_t registration_id;
326 u_int32_t flags;
327 unsigned flow_result_read : 1;
328 unsigned defunct : 1;
329 void *interface_handle;
330 necp_client_flow_cb interface_cb;
331 struct necp_client *client;
332 LIST_HEAD(_necp_registration_flow_list, necp_client_flow) flow_list;
333 u_int64_t last_interface_details __attribute__((aligned(sizeof(u_int64_t))));
334};
335
336static int necp_client_flow_id_cmp(struct necp_client_flow_registration *flow0, struct necp_client_flow_registration *flow1);
337
338RB_HEAD(_necp_client_flow_tree, necp_client_flow_registration);
339RB_PROTOTYPE_PREV(_necp_client_flow_tree, necp_client_flow_registration, client_link, necp_client_flow_id_cmp);
340RB_GENERATE_PREV(_necp_client_flow_tree, necp_client_flow_registration, client_link, necp_client_flow_id_cmp);
341
342#define NECP_CLIENT_INTERFACE_OPTION_STATIC_COUNT 4
343#define NECP_CLIENT_MAX_INTERFACE_OPTIONS 16
344
345#define NECP_CLIENT_INTERFACE_OPTION_EXTRA_COUNT (NECP_CLIENT_MAX_INTERFACE_OPTIONS - NECP_CLIENT_INTERFACE_OPTION_STATIC_COUNT)
346
39037602 347struct necp_client {
5ba3f43e
A
348 RB_ENTRY(necp_client) link;
349 RB_ENTRY(necp_client) global_link;
5ba3f43e
A
350
351 decl_lck_mtx_data(, lock);
352 decl_lck_mtx_data(, route_lock);
cb323159 353 os_refcnt_t reference_count;
39037602
A
354
355 uuid_t client_id;
5ba3f43e 356 unsigned result_read : 1;
5ba3f43e 357 unsigned allow_multiple_flows : 1;
d9a64523 358 unsigned legacy_client_is_flow : 1;
5ba3f43e 359
5ba3f43e 360 unsigned platform_binary : 1;
39037602
A
361
362 size_t result_length;
363 u_int8_t result[NECP_MAX_CLIENT_RESULT_SIZE];
364
5ba3f43e
A
365 necp_policy_id policy_id;
366
cb323159 367 u_int8_t ip_protocol;
5ba3f43e 368 int proc_pid;
39037602 369
cb323159
A
370 u_int64_t delegated_upid;
371
d9a64523 372 struct _necp_client_flow_tree flow_registrations;
39037602
A
373 LIST_HEAD(_necp_client_assertion_list, necp_client_assertion) assertion_list;
374
5ba3f43e
A
375 struct rtentry *current_route;
376
d9a64523
A
377 struct necp_client_interface_option interface_options[NECP_CLIENT_INTERFACE_OPTION_STATIC_COUNT];
378 struct necp_client_interface_option *extra_interface_options;
379 u_int8_t interface_option_count; // Number in interface_options + extra_interface_options
380
381 struct necp_client_result_netagent failed_trigger_agent;
382
383 void *agent_handle;
39037602 384
ea3f0419
A
385 uuid_t override_euuid;
386
cb323159 387
39037602
A
388 size_t parameters_length;
389 u_int8_t parameters[0];
390};
391
5ba3f43e
A
392#define NECP_CLIENT_LOCK(_c) lck_mtx_lock(&_c->lock)
393#define NECP_CLIENT_UNLOCK(_c) lck_mtx_unlock(&_c->lock)
394#define NECP_CLIENT_ASSERT_LOCKED(_c) LCK_MTX_ASSERT(&_c->lock, LCK_MTX_ASSERT_OWNED)
395#define NECP_CLIENT_ASSERT_UNLOCKED(_c) LCK_MTX_ASSERT(&_c->lock, LCK_MTX_ASSERT_NOTOWNED)
396
397#define NECP_CLIENT_ROUTE_LOCK(_c) lck_mtx_lock(&_c->route_lock)
398#define NECP_CLIENT_ROUTE_UNLOCK(_c) lck_mtx_unlock(&_c->route_lock)
399
400static void necp_client_retain_locked(struct necp_client *client);
cb323159 401
5ba3f43e 402static bool necp_client_release_locked(struct necp_client *client);
cb323159 403static bool necp_client_release(struct necp_client *client);
5ba3f43e
A
404
405static void
406necp_client_add_assertion(struct necp_client *client, uuid_t netagent_uuid);
407
408static bool
409necp_client_remove_assertion(struct necp_client *client, uuid_t netagent_uuid);
410
d9a64523
A
411LIST_HEAD(_necp_flow_registration_list, necp_client_flow_registration);
412static struct _necp_flow_registration_list necp_collect_stats_flow_list;
5ba3f43e 413
d9a64523
A
414struct necp_flow_defunct {
415 LIST_ENTRY(necp_flow_defunct) chain;
5ba3f43e 416
d9a64523 417 uuid_t flow_id;
5ba3f43e 418 uuid_t nexus_agent;
d9a64523 419 void *agent_handle;
5ba3f43e 420 int proc_pid;
cb323159
A
421 u_int32_t flags;
422 struct necp_client_agent_parameters close_parameters;
423 bool has_close_parameters;
5ba3f43e
A
424};
425
d9a64523 426LIST_HEAD(_necp_flow_defunct_list, necp_flow_defunct);
5ba3f43e
A
427
428static int necp_client_id_cmp(struct necp_client *client0, struct necp_client *client1);
429
430RB_HEAD(_necp_client_tree, necp_client);
431RB_PROTOTYPE_PREV(_necp_client_tree, necp_client, link, necp_client_id_cmp);
432RB_GENERATE_PREV(_necp_client_tree, necp_client, link, necp_client_id_cmp);
433
434RB_HEAD(_necp_client_global_tree, necp_client);
435RB_PROTOTYPE_PREV(_necp_client_global_tree, necp_client, global_link, necp_client_id_cmp);
436RB_GENERATE_PREV(_necp_client_global_tree, necp_client, global_link, necp_client_id_cmp);
437
d9a64523
A
438RB_HEAD(_necp_fd_flow_tree, necp_client_flow_registration);
439RB_PROTOTYPE_PREV(_necp_fd_flow_tree, necp_client_flow_registration, fd_link, necp_client_flow_id_cmp);
440RB_GENERATE_PREV(_necp_fd_flow_tree, necp_client_flow_registration, fd_link, necp_client_flow_id_cmp);
441
442RB_HEAD(_necp_client_flow_global_tree, necp_client_flow_registration);
443RB_PROTOTYPE_PREV(_necp_client_flow_global_tree, necp_client_flow_registration, global_link, necp_client_flow_id_cmp);
444RB_GENERATE_PREV(_necp_client_flow_global_tree, necp_client_flow_registration, global_link, necp_client_flow_id_cmp);
445
5ba3f43e 446static struct _necp_client_global_tree necp_client_global_tree;
d9a64523 447static struct _necp_client_flow_global_tree necp_client_flow_global_tree;
5ba3f43e
A
448
449struct necp_client_update {
450 TAILQ_ENTRY(necp_client_update) chain;
451
452 uuid_t client_id;
453
454 size_t update_length;
455 struct necp_client_observer_update update;
456};
457
a39ff7e2 458
0a7de745
A
459#define NAIF_ATTACHED 0x1 // arena is attached to list
460#define NAIF_REDIRECT 0x2 // arena mmap has been redirected
461#define NAIF_DEFUNCT 0x4 // arena is now defunct
d9a64523 462
39037602 463struct necp_fd_data {
5ba3f43e 464 u_int8_t necp_fd_type;
39037602 465 LIST_ENTRY(necp_fd_data) chain;
5ba3f43e 466 struct _necp_client_tree clients;
d9a64523 467 struct _necp_fd_flow_tree flows;
5ba3f43e
A
468 TAILQ_HEAD(_necp_client_update_list, necp_client_update) update_list;
469 int update_count;
39037602 470 int flags;
cb323159
A
471
472 unsigned background : 1;
473
39037602
A
474 int proc_pid;
475 decl_lck_mtx_data(, fd_lock);
476 struct selinfo si;
477};
478
5ba3f43e
A
479#define NECP_FD_LOCK(_f) lck_mtx_lock(&_f->fd_lock)
480#define NECP_FD_UNLOCK(_f) lck_mtx_unlock(&_f->fd_lock)
481#define NECP_FD_ASSERT_LOCKED(_f) LCK_MTX_ASSERT(&_f->fd_lock, LCK_MTX_ASSERT_OWNED)
482#define NECP_FD_ASSERT_UNLOCKED(_f) LCK_MTX_ASSERT(&_f->fd_lock, LCK_MTX_ASSERT_NOTOWNED)
483
39037602 484static LIST_HEAD(_necp_fd_list, necp_fd_data) necp_fd_list;
5ba3f43e
A
485static LIST_HEAD(_necp_fd_observer_list, necp_fd_data) necp_fd_observer_list;
486
0a7de745
A
487#define NECP_CLIENT_FD_ZONE_MAX 128
488#define NECP_CLIENT_FD_ZONE_NAME "necp.clientfd"
5ba3f43e 489
0a7de745
A
490static unsigned int necp_client_fd_size; /* size of zone element */
491static struct zone *necp_client_fd_zone; /* zone for necp_fd_data */
5ba3f43e 492
0a7de745
A
493#define NECP_FLOW_ZONE_NAME "necp.flow"
494#define NECP_FLOW_REGISTRATION_ZONE_NAME "necp.flowregistration"
5ba3f43e 495
0a7de745
A
496static unsigned int necp_flow_size; /* size of necp_client_flow */
497static struct mcache *necp_flow_cache; /* cache for necp_client_flow */
d9a64523 498
0a7de745
A
499static unsigned int necp_flow_registration_size; /* size of necp_client_flow_registration */
500static struct mcache *necp_flow_registration_cache; /* cache for necp_client_flow_registration */
d9a64523 501
0a7de745
A
502#define NECP_ARENA_INFO_ZONE_MAX 128
503#define NECP_ARENA_INFO_ZONE_NAME "necp.arenainfo"
a39ff7e2 504
39037602 505
0a7de745
A
506static lck_grp_attr_t *necp_fd_grp_attr = NULL;
507static lck_attr_t *necp_fd_mtx_attr = NULL;
508static lck_grp_t *necp_fd_mtx_grp = NULL;
5ba3f43e 509
39037602 510decl_lck_rw_data(static, necp_fd_lock);
5ba3f43e
A
511decl_lck_rw_data(static, necp_observer_lock);
512decl_lck_rw_data(static, necp_client_tree_lock);
d9a64523 513decl_lck_rw_data(static, necp_flow_tree_lock);
5ba3f43e
A
514decl_lck_rw_data(static, necp_collect_stats_list_lock);
515
516#define NECP_STATS_LIST_LOCK_EXCLUSIVE() lck_rw_lock_exclusive(&necp_collect_stats_list_lock)
517#define NECP_STATS_LIST_LOCK_SHARED() lck_rw_lock_shared(&necp_collect_stats_list_lock)
518#define NECP_STATS_LIST_UNLOCK() lck_rw_done(&necp_collect_stats_list_lock)
519
520#define NECP_CLIENT_TREE_LOCK_EXCLUSIVE() lck_rw_lock_exclusive(&necp_client_tree_lock)
521#define NECP_CLIENT_TREE_LOCK_SHARED() lck_rw_lock_shared(&necp_client_tree_lock)
522#define NECP_CLIENT_TREE_UNLOCK() lck_rw_done(&necp_client_tree_lock)
d9a64523
A
523#define NECP_CLIENT_TREE_ASSERT_LOCKED() LCK_RW_ASSERT(&necp_client_tree_lock, LCK_RW_ASSERT_HELD)
524
525#define NECP_FLOW_TREE_LOCK_EXCLUSIVE() lck_rw_lock_exclusive(&necp_flow_tree_lock)
526#define NECP_FLOW_TREE_LOCK_SHARED() lck_rw_lock_shared(&necp_flow_tree_lock)
527#define NECP_FLOW_TREE_UNLOCK() lck_rw_done(&necp_flow_tree_lock)
528#define NECP_FLOW_TREE_ASSERT_LOCKED() LCK_RW_ASSERT(&necp_flow_tree_lock, LCK_RW_ASSERT_HELD)
5ba3f43e
A
529
530#define NECP_FD_LIST_LOCK_EXCLUSIVE() lck_rw_lock_exclusive(&necp_fd_lock)
531#define NECP_FD_LIST_LOCK_SHARED() lck_rw_lock_shared(&necp_fd_lock)
532#define NECP_FD_LIST_UNLOCK() lck_rw_done(&necp_fd_lock)
533
534#define NECP_OBSERVER_LIST_LOCK_EXCLUSIVE() lck_rw_lock_exclusive(&necp_observer_lock)
535#define NECP_OBSERVER_LIST_LOCK_SHARED() lck_rw_lock_shared(&necp_observer_lock)
536#define NECP_OBSERVER_LIST_UNLOCK() lck_rw_done(&necp_observer_lock)
537
538// Locking Notes
539
540// Take NECP_FD_LIST_LOCK when accessing or modifying the necp_fd_list
541// Take NECP_CLIENT_TREE_LOCK when accessing or modifying the necp_client_global_tree
d9a64523
A
542// Take NECP_FLOW_TREE_LOCK when accessing or modifying the necp_client_flow_global_tree
543// Take NECP_STATS_LIST_LOCK when accessing or modifying the necp_collect_stats_flow_list
5ba3f43e
A
544// Take NECP_FD_LOCK when accessing or modifying an necp_fd_data entry
545// Take NECP_CLIENT_LOCK when accessing or modifying a single necp_client
546// Take NECP_CLIENT_ROUTE_LOCK when accessing or modifying a client's route
547
548// Precedence, where 1 is the first lock that must be taken
549// 1. NECP_FD_LIST_LOCK
550// 2. NECP_FD_LOCK (any)
551// 3. NECP_CLIENT_TREE_LOCK
552// 4. NECP_CLIENT_LOCK (any)
d9a64523
A
553// 5. NECP_FLOW_TREE_LOCK
554// 6. NECP_STATS_LIST_LOCK
555// 7. NECP_CLIENT_ROUTE_LOCK (any)
5ba3f43e
A
556
557static thread_call_t necp_client_update_tcall;
39037602 558
39037602
A
559
560/// NECP file descriptor functions
561
39037602
A
562static void
563necp_fd_notify(struct necp_fd_data *fd_data, bool locked)
564{
565 struct selinfo *si = &fd_data->si;
566
567 if (!locked) {
5ba3f43e 568 NECP_FD_LOCK(fd_data);
39037602
A
569 }
570
571 selwakeup(si);
572
573 // use a non-zero hint to tell the notification from the
574 // call done in kqueue_scan() which uses 0
575 KNOTE(&si->si_note, 1); // notification
576
577 if (!locked) {
5ba3f43e 578 NECP_FD_UNLOCK(fd_data);
39037602
A
579 }
580}
581
d9a64523
A
582static inline bool
583necp_client_has_unread_flows(struct necp_client *client)
584{
585 NECP_CLIENT_ASSERT_LOCKED(client);
586 struct necp_client_flow_registration *flow_registration = NULL;
587 RB_FOREACH(flow_registration, _necp_client_flow_tree, &client->flow_registrations) {
588 if (!flow_registration->flow_result_read) {
589 return true;
590 }
591 }
592 return false;
593}
594
39037602
A
595static int
596necp_fd_poll(struct necp_fd_data *fd_data, int events, void *wql, struct proc *p, int is_kevent)
597{
598#pragma unused(wql, p, is_kevent)
599 u_int revents = 0;
39037602
A
600
601 u_int want_rx = events & (POLLIN | POLLRDNORM);
602 if (want_rx) {
5ba3f43e
A
603 if (fd_data->flags & NECP_OPEN_FLAG_PUSH_OBSERVER) {
604 // Push-mode observers are readable when they have a new update
605 if (!TAILQ_EMPTY(&fd_data->update_list)) {
606 revents |= want_rx;
607 }
608 } else {
609 // Standard fds are readable when some client is unread
610 struct necp_client *client = NULL;
611 bool has_unread_clients = FALSE;
612 RB_FOREACH(client, _necp_client_tree, &fd_data->clients) {
613 NECP_CLIENT_LOCK(client);
d9a64523 614 if (!client->result_read || necp_client_has_unread_flows(client)) {
5ba3f43e
A
615 has_unread_clients = TRUE;
616 }
617 NECP_CLIENT_UNLOCK(client);
0a7de745 618 if (has_unread_clients) {
5ba3f43e
A
619 break;
620 }
39037602 621 }
39037602 622
5ba3f43e
A
623 if (has_unread_clients) {
624 revents |= want_rx;
625 }
39037602
A
626 }
627 }
628
0a7de745 629 return revents;
39037602
A
630}
631
d9a64523
A
632static inline void
633necp_generate_client_id(uuid_t client_id, bool is_flow)
634{
635 uuid_generate_random(client_id);
636
637 if (is_flow) {
638 client_id[9] |= 0x01;
639 } else {
640 client_id[9] &= ~0x01;
641 }
642}
643
644static inline bool
645necp_client_id_is_flow(uuid_t client_id)
646{
0a7de745 647 return client_id[9] & 0x01;
d9a64523
A
648}
649
5ba3f43e 650static struct necp_client *
d9a64523
A
651necp_find_client_and_lock(uuid_t client_id)
652{
653 NECP_CLIENT_TREE_ASSERT_LOCKED();
654
655 struct necp_client *client = NULL;
656
657 if (necp_client_id_is_flow(client_id)) {
658 NECP_FLOW_TREE_LOCK_SHARED();
659 struct necp_client_flow_registration find;
660 uuid_copy(find.registration_id, client_id);
661 struct necp_client_flow_registration *flow = RB_FIND(_necp_client_flow_global_tree, &necp_client_flow_global_tree, &find);
662 if (flow != NULL) {
663 client = flow->client;
664 }
665 NECP_FLOW_TREE_UNLOCK();
666 } else {
667 struct necp_client find;
668 uuid_copy(find.client_id, client_id);
669 client = RB_FIND(_necp_client_global_tree, &necp_client_global_tree, &find);
670 }
671
672 if (client != NULL) {
673 NECP_CLIENT_LOCK(client);
674 }
675
0a7de745 676 return client;
d9a64523
A
677}
678
679static struct necp_client_flow_registration *
680necp_client_find_flow(struct necp_client *client, uuid_t flow_id)
681{
682 NECP_CLIENT_ASSERT_LOCKED(client);
683 struct necp_client_flow_registration *flow = NULL;
684
685 if (necp_client_id_is_flow(flow_id)) {
686 struct necp_client_flow_registration find;
687 uuid_copy(find.registration_id, flow_id);
688 flow = RB_FIND(_necp_client_flow_tree, &client->flow_registrations, &find);
689 } else {
690 flow = RB_ROOT(&client->flow_registrations);
691 }
692
0a7de745 693 return flow;
d9a64523
A
694}
695
696static struct necp_client *
697necp_client_fd_find_client_unlocked(struct necp_fd_data *client_fd, uuid_t client_id)
5ba3f43e 698{
5ba3f43e 699 NECP_FD_ASSERT_LOCKED(client_fd);
d9a64523
A
700 struct necp_client *client = NULL;
701
702 if (necp_client_id_is_flow(client_id)) {
703 struct necp_client_flow_registration find;
704 uuid_copy(find.registration_id, client_id);
705 struct necp_client_flow_registration *flow = RB_FIND(_necp_fd_flow_tree, &client_fd->flows, &find);
706 if (flow != NULL) {
707 client = flow->client;
708 }
709 } else {
710 struct necp_client find;
711 uuid_copy(find.client_id, client_id);
712 client = RB_FIND(_necp_client_tree, &client_fd->clients, &find);
713 }
714
0a7de745 715 return client;
d9a64523 716}
5ba3f43e 717
d9a64523
A
718static struct necp_client *
719necp_client_fd_find_client_and_lock(struct necp_fd_data *client_fd, uuid_t client_id)
720{
721 struct necp_client *client = necp_client_fd_find_client_unlocked(client_fd, client_id);
5ba3f43e
A
722 if (client != NULL) {
723 NECP_CLIENT_LOCK(client);
724 }
725
0a7de745 726 return client;
5ba3f43e
A
727}
728
729static inline int
730necp_client_id_cmp(struct necp_client *client0, struct necp_client *client1)
731{
0a7de745 732 return uuid_compare(client0->client_id, client1->client_id);
5ba3f43e
A
733}
734
d9a64523
A
735static inline int
736necp_client_flow_id_cmp(struct necp_client_flow_registration *flow0, struct necp_client_flow_registration *flow1)
737{
0a7de745 738 return uuid_compare(flow0->registration_id, flow1->registration_id);
d9a64523
A
739}
740
39037602
A
741static int
742necpop_select(struct fileproc *fp, int which, void *wql, vfs_context_t ctx)
743{
744#pragma unused(fp, which, wql, ctx)
0a7de745 745 return 0;
39037602
A
746 struct necp_fd_data *fd_data = NULL;
747 int revents = 0;
748 int events = 0;
749 proc_t procp;
750
751 fd_data = (struct necp_fd_data *)fp->f_fglob->fg_data;
752 if (fd_data == NULL) {
0a7de745 753 return 0;
39037602
A
754 }
755
756 procp = vfs_context_proc(ctx);
757
758 switch (which) {
0a7de745
A
759 case FREAD: {
760 events = POLLIN;
761 break;
762 }
39037602 763
0a7de745
A
764 default: {
765 return 1;
766 }
39037602
A
767 }
768
5ba3f43e 769 NECP_FD_LOCK(fd_data);
39037602 770 revents = necp_fd_poll(fd_data, events, wql, procp, 0);
5ba3f43e 771 NECP_FD_UNLOCK(fd_data);
39037602 772
0a7de745 773 return (events & revents) ? 1 : 0;
39037602
A
774}
775
776static void
777necp_fd_knrdetach(struct knote *kn)
778{
779 struct necp_fd_data *fd_data = (struct necp_fd_data *)kn->kn_hook;
780 struct selinfo *si = &fd_data->si;
781
5ba3f43e 782 NECP_FD_LOCK(fd_data);
39037602 783 KNOTE_DETACH(&si->si_note, kn);
5ba3f43e 784 NECP_FD_UNLOCK(fd_data);
39037602
A
785}
786
787static int
788necp_fd_knread(struct knote *kn, long hint)
789{
790#pragma unused(kn, hint)
791 return 1; /* assume we are ready */
792}
793
794static int
cb323159 795necp_fd_knrprocess(struct knote *kn, struct kevent_qos_s *kev)
39037602 796{
39037602
A
797 struct necp_fd_data *fd_data;
798 int revents;
799 int res;
800
801 fd_data = (struct necp_fd_data *)kn->kn_hook;
802
5ba3f43e 803 NECP_FD_LOCK(fd_data);
39037602
A
804 revents = necp_fd_poll(fd_data, POLLIN, NULL, current_proc(), 1);
805 res = ((revents & POLLIN) != 0);
806 if (res) {
cb323159 807 knote_fill_kevent(kn, kev, 0);
39037602 808 }
5ba3f43e 809 NECP_FD_UNLOCK(fd_data);
0a7de745 810 return res;
39037602
A
811}
812
5ba3f43e 813static int
cb323159 814necp_fd_knrtouch(struct knote *kn, struct kevent_qos_s *kev)
39037602
A
815{
816#pragma unused(kev)
817 struct necp_fd_data *fd_data;
818 int revents;
819
820 fd_data = (struct necp_fd_data *)kn->kn_hook;
821
5ba3f43e 822 NECP_FD_LOCK(fd_data);
39037602 823 revents = necp_fd_poll(fd_data, POLLIN, NULL, current_proc(), 1);
5ba3f43e 824 NECP_FD_UNLOCK(fd_data);
39037602 825
0a7de745 826 return (revents & POLLIN) != 0;
39037602
A
827}
828
5ba3f43e 829SECURITY_READ_ONLY_EARLY(struct filterops) necp_fd_rfiltops = {
39037602
A
830 .f_isfd = 1,
831 .f_detach = necp_fd_knrdetach,
832 .f_event = necp_fd_knread,
833 .f_touch = necp_fd_knrtouch,
834 .f_process = necp_fd_knrprocess,
835};
836
837static int
5ba3f43e 838necpop_kqfilter(struct fileproc *fp, struct knote *kn,
cb323159 839 __unused struct kevent_qos_s *kev)
39037602 840{
39037602
A
841 struct necp_fd_data *fd_data = NULL;
842 int revents;
843
844 if (kn->kn_filter != EVFILT_READ) {
845 NECPLOG(LOG_ERR, "bad filter request %d", kn->kn_filter);
cb323159 846 knote_set_error(kn, EINVAL);
0a7de745 847 return 0;
39037602
A
848 }
849
cb323159 850 fd_data = (struct necp_fd_data *)fp->f_fglob->fg_data;
39037602
A
851 if (fd_data == NULL) {
852 NECPLOG0(LOG_ERR, "No channel for kqfilter");
cb323159 853 knote_set_error(kn, ENOENT);
0a7de745 854 return 0;
39037602
A
855 }
856
5ba3f43e 857 NECP_FD_LOCK(fd_data);
39037602
A
858 kn->kn_filtid = EVFILTID_NECP_FD;
859 kn->kn_hook = fd_data;
860 KNOTE_ATTACH(&fd_data->si.si_note, kn);
861
862 revents = necp_fd_poll(fd_data, POLLIN, NULL, current_proc(), 1);
863
5ba3f43e 864 NECP_FD_UNLOCK(fd_data);
39037602 865
0a7de745 866 return (revents & POLLIN) != 0;
39037602
A
867}
868
d9a64523
A
869#define INTERFACE_FLAGS_SHIFT 32
870#define INTERFACE_FLAGS_MASK 0xffff
871#define INTERFACE_INDEX_SHIFT 0
872#define INTERFACE_INDEX_MASK 0xffffffff
5ba3f43e 873
d9a64523
A
874static uint64_t
875combine_interface_details(uint32_t interface_index, uint16_t interface_flags)
5ba3f43e 876{
0a7de745
A
877 return ((uint64_t)interface_flags & INTERFACE_FLAGS_MASK) << INTERFACE_FLAGS_SHIFT |
878 ((uint64_t)interface_index & INTERFACE_INDEX_MASK) << INTERFACE_INDEX_SHIFT;
5ba3f43e
A
879}
880
d9a64523 881
39037602 882static void
d9a64523 883necp_defunct_flow_registration(struct necp_client *client,
0a7de745
A
884 struct necp_client_flow_registration *flow_registration,
885 struct _necp_flow_defunct_list *defunct_list)
39037602 886{
a39ff7e2 887 NECP_CLIENT_ASSERT_LOCKED(client);
d9a64523
A
888
889 if (!flow_registration->defunct) {
5ba3f43e
A
890 bool needs_defunct = false;
891 struct necp_client_flow *search_flow = NULL;
d9a64523 892 LIST_FOREACH(search_flow, &flow_registration->flow_list, flow_chain) {
5ba3f43e 893 if (search_flow->nexus &&
0a7de745 894 !uuid_is_null(search_flow->u.nexus_agent)) {
5ba3f43e
A
895 // Save defunct values for the nexus
896 if (defunct_list != NULL) {
897 // Sleeping alloc won't fail; copy only what's necessary
0a7de745
A
898 struct necp_flow_defunct *flow_defunct = _MALLOC(sizeof(struct necp_flow_defunct),
899 M_NECP, M_WAITOK | M_ZERO);
d9a64523
A
900 uuid_copy(flow_defunct->nexus_agent, search_flow->u.nexus_agent);
901 uuid_copy(flow_defunct->flow_id, ((flow_registration->flags & NECP_CLIENT_FLOW_FLAGS_USE_CLIENT_ID) ?
0a7de745
A
902 client->client_id :
903 flow_registration->registration_id));
d9a64523
A
904 flow_defunct->proc_pid = client->proc_pid;
905 flow_defunct->agent_handle = client->agent_handle;
cb323159 906 flow_defunct->flags = flow_registration->flags;
5ba3f43e 907 // Add to the list provided by caller
d9a64523 908 LIST_INSERT_HEAD(defunct_list, flow_defunct, chain);
5ba3f43e
A
909 }
910
911 needs_defunct = true;
912 }
913 }
914
915 if (needs_defunct) {
d9a64523 916
5ba3f43e 917 // Only set defunct if there was some assigned flow
d9a64523 918 flow_registration->defunct = true;
39037602 919 }
39037602
A
920 }
921}
922
d9a64523
A
923static void
924necp_defunct_client_for_policy(struct necp_client *client,
0a7de745 925 struct _necp_flow_defunct_list *defunct_list)
d9a64523
A
926{
927 NECP_CLIENT_ASSERT_LOCKED(client);
928
929 struct necp_client_flow_registration *flow_registration = NULL;
930 RB_FOREACH(flow_registration, _necp_client_flow_tree, &client->flow_registrations) {
931 necp_defunct_flow_registration(client, flow_registration, defunct_list);
932 }
933}
934
39037602 935static void
5ba3f43e
A
936necp_client_free(struct necp_client *client)
937{
938 NECP_CLIENT_ASSERT_LOCKED(client);
939
940 NECP_CLIENT_UNLOCK(client);
941
d9a64523
A
942 FREE(client->extra_interface_options, M_NECP);
943 client->extra_interface_options = NULL;
944
5ba3f43e
A
945 lck_mtx_destroy(&client->route_lock, necp_fd_mtx_grp);
946 lck_mtx_destroy(&client->lock, necp_fd_mtx_grp);
947
948 FREE(client, M_NECP);
949}
950
951static void
952necp_client_retain_locked(struct necp_client *client)
953{
954 NECP_CLIENT_ASSERT_LOCKED(client);
955
cb323159 956 os_ref_retain_locked(&client->reference_count);
5ba3f43e
A
957}
958
5ba3f43e
A
959
960static bool
961necp_client_release_locked(struct necp_client *client)
962{
963 NECP_CLIENT_ASSERT_LOCKED(client);
964
cb323159
A
965 os_ref_count_t count = os_ref_release_locked(&client->reference_count);
966 if (count == 0) {
5ba3f43e
A
967 necp_client_free(client);
968 }
969
cb323159 970 return count == 0;
5ba3f43e
A
971}
972
cb323159
A
973static bool
974necp_client_release(struct necp_client *client)
975{
976 bool last_ref;
977
978 NECP_CLIENT_LOCK(client);
979 if (!(last_ref = necp_client_release_locked(client))) {
980 NECP_CLIENT_UNLOCK(client);
981 }
982
983 return last_ref;
984}
5ba3f43e
A
985
986static void
987necp_client_update_observer_add_internal(struct necp_fd_data *observer_fd, struct necp_client *client)
988{
989 NECP_FD_LOCK(observer_fd);
990
991 if (observer_fd->update_count >= necp_observer_message_limit) {
992 NECP_FD_UNLOCK(observer_fd);
993 return;
994 }
995
996 struct necp_client_update *client_update = _MALLOC(sizeof(struct necp_client_update) + client->parameters_length,
0a7de745 997 M_NECP, M_WAITOK | M_ZERO);
5ba3f43e
A
998 if (client_update != NULL) {
999 client_update->update_length = sizeof(struct necp_client_observer_update) + client->parameters_length;
1000 uuid_copy(client_update->client_id, client->client_id);
1001 client_update->update.update_type = NECP_CLIENT_UPDATE_TYPE_PARAMETERS;
1002 memcpy(client_update->update.tlv_buffer, client->parameters, client->parameters_length);
1003 TAILQ_INSERT_TAIL(&observer_fd->update_list, client_update, chain);
1004 observer_fd->update_count++;
1005
1006 necp_fd_notify(observer_fd, true);
1007 }
1008
1009 NECP_FD_UNLOCK(observer_fd);
1010}
1011
1012static void
1013necp_client_update_observer_update_internal(struct necp_fd_data *observer_fd, struct necp_client *client)
1014{
1015 NECP_FD_LOCK(observer_fd);
1016
1017 if (observer_fd->update_count >= necp_observer_message_limit) {
1018 NECP_FD_UNLOCK(observer_fd);
1019 return;
1020 }
1021
1022 struct necp_client_update *client_update = _MALLOC(sizeof(struct necp_client_update) + client->result_length,
0a7de745 1023 M_NECP, M_WAITOK | M_ZERO);
5ba3f43e
A
1024 if (client_update != NULL) {
1025 client_update->update_length = sizeof(struct necp_client_observer_update) + client->result_length;
1026 uuid_copy(client_update->client_id, client->client_id);
1027 client_update->update.update_type = NECP_CLIENT_UPDATE_TYPE_RESULT;
1028 memcpy(client_update->update.tlv_buffer, client->result, client->result_length);
1029 TAILQ_INSERT_TAIL(&observer_fd->update_list, client_update, chain);
1030 observer_fd->update_count++;
1031
1032 necp_fd_notify(observer_fd, true);
1033 }
1034
1035 NECP_FD_UNLOCK(observer_fd);
1036}
1037
1038static void
1039necp_client_update_observer_remove_internal(struct necp_fd_data *observer_fd, struct necp_client *client)
1040{
1041 NECP_FD_LOCK(observer_fd);
1042
1043 if (observer_fd->update_count >= necp_observer_message_limit) {
1044 NECP_FD_UNLOCK(observer_fd);
1045 return;
1046 }
1047
1048 struct necp_client_update *client_update = _MALLOC(sizeof(struct necp_client_update),
0a7de745 1049 M_NECP, M_WAITOK | M_ZERO);
5ba3f43e
A
1050 if (client_update != NULL) {
1051 client_update->update_length = sizeof(struct necp_client_observer_update);
1052 uuid_copy(client_update->client_id, client->client_id);
1053 client_update->update.update_type = NECP_CLIENT_UPDATE_TYPE_REMOVE;
1054 TAILQ_INSERT_TAIL(&observer_fd->update_list, client_update, chain);
1055 observer_fd->update_count++;
1056
1057 necp_fd_notify(observer_fd, true);
1058 }
1059
1060 NECP_FD_UNLOCK(observer_fd);
1061}
1062
1063static void
1064necp_client_update_observer_add(struct necp_client *client)
1065{
1066 NECP_OBSERVER_LIST_LOCK_SHARED();
1067
1068 if (LIST_EMPTY(&necp_fd_observer_list)) {
1069 // No observers, bail
1070 NECP_OBSERVER_LIST_UNLOCK();
1071 return;
1072 }
1073
1074 struct necp_fd_data *observer_fd = NULL;
1075 LIST_FOREACH(observer_fd, &necp_fd_observer_list, chain) {
1076 necp_client_update_observer_add_internal(observer_fd, client);
1077 }
1078
1079 NECP_OBSERVER_LIST_UNLOCK();
1080}
1081
1082static void
1083necp_client_update_observer_update(struct necp_client *client)
1084{
1085 NECP_OBSERVER_LIST_LOCK_SHARED();
1086
1087 if (LIST_EMPTY(&necp_fd_observer_list)) {
1088 // No observers, bail
1089 NECP_OBSERVER_LIST_UNLOCK();
1090 return;
1091 }
1092
1093 struct necp_fd_data *observer_fd = NULL;
1094 LIST_FOREACH(observer_fd, &necp_fd_observer_list, chain) {
1095 necp_client_update_observer_update_internal(observer_fd, client);
1096 }
1097
1098 NECP_OBSERVER_LIST_UNLOCK();
1099}
1100
1101static void
1102necp_client_update_observer_remove(struct necp_client *client)
39037602 1103{
5ba3f43e
A
1104 NECP_OBSERVER_LIST_LOCK_SHARED();
1105
1106 if (LIST_EMPTY(&necp_fd_observer_list)) {
1107 // No observers, bail
1108 NECP_OBSERVER_LIST_UNLOCK();
1109 return;
1110 }
1111
1112 struct necp_fd_data *observer_fd = NULL;
1113 LIST_FOREACH(observer_fd, &necp_fd_observer_list, chain) {
1114 necp_client_update_observer_remove_internal(observer_fd, client);
1115 }
39037602 1116
5ba3f43e
A
1117 NECP_OBSERVER_LIST_UNLOCK();
1118}
1119
1120static void
d9a64523 1121necp_destroy_client_flow_registration(struct necp_client *client,
0a7de745
A
1122 struct necp_client_flow_registration *flow_registration,
1123 pid_t pid, bool abort)
5ba3f43e 1124{
d9a64523 1125 NECP_CLIENT_ASSERT_LOCKED(client);
5ba3f43e 1126
cb323159
A
1127 bool has_close_parameters = false;
1128 struct necp_client_agent_parameters close_parameters = {};
1129 memset(close_parameters.u.close_token, 0, sizeof(close_parameters.u.close_token));
5ba3f43e 1130
5ba3f43e
A
1131 struct necp_client_flow *search_flow = NULL;
1132 struct necp_client_flow *temp_flow = NULL;
d9a64523 1133 LIST_FOREACH_SAFE(search_flow, &flow_registration->flow_list, flow_chain, temp_flow) {
5ba3f43e 1134 if (search_flow->nexus &&
0a7de745 1135 !uuid_is_null(search_flow->u.nexus_agent)) {
5ba3f43e 1136 // Note that if we had defuncted the client earlier, this would result in a harmless ENOENT
cb323159
A
1137 u_int8_t message_type = (abort ? NETAGENT_MESSAGE_TYPE_ABORT_NEXUS :
1138 NETAGENT_MESSAGE_TYPE_CLOSE_NEXUS);
1139 if (((flow_registration->flags & NECP_CLIENT_FLOW_FLAGS_BROWSE) ||
1140 (flow_registration->flags & NECP_CLIENT_FLOW_FLAGS_RESOLVE)) &&
1141 !(flow_registration->flags & NECP_CLIENT_FLOW_FLAGS_ALLOW_NEXUS)) {
1142 message_type = NETAGENT_MESSAGE_TYPE_CLIENT_UNASSERT;
1143 }
1144 int netagent_error = netagent_client_message_with_params(search_flow->u.nexus_agent,
0a7de745
A
1145 ((flow_registration->flags & NECP_CLIENT_FLOW_FLAGS_USE_CLIENT_ID) ?
1146 client->client_id :
1147 flow_registration->registration_id),
1148 pid, client->agent_handle,
cb323159
A
1149 message_type,
1150 has_close_parameters ? &close_parameters : NULL,
1151 NULL, 0);
5ba3f43e 1152 if (netagent_error != 0 && netagent_error != ENOENT) {
cb323159 1153 NECPLOG(LOG_ERR, "necp_client_remove close nexus error (%d) MESSAGE TYPE %u", netagent_error, message_type);
39037602 1154 }
5ba3f43e 1155 uuid_clear(search_flow->u.nexus_agent);
39037602 1156 }
5ba3f43e
A
1157 if (search_flow->assigned_results != NULL) {
1158 FREE(search_flow->assigned_results, M_NETAGENT);
1159 search_flow->assigned_results = NULL;
1160 }
1161 LIST_REMOVE(search_flow, flow_chain);
1162 if (search_flow->socket) {
1163 OSDecrementAtomic(&necp_socket_flow_count);
1164 } else {
1165 OSDecrementAtomic(&necp_if_flow_count);
1166 }
a39ff7e2 1167 mcache_free(necp_flow_cache, search_flow);
39037602
A
1168 }
1169
d9a64523
A
1170 RB_REMOVE(_necp_client_flow_tree, &client->flow_registrations, flow_registration);
1171 flow_registration->client = NULL;
1172
1173 mcache_free(necp_flow_registration_cache, flow_registration);
1174}
1175
1176static void
1177necp_destroy_client(struct necp_client *client, pid_t pid, bool abort)
1178{
1179 NECP_CLIENT_ASSERT_UNLOCKED(client);
1180
1181 necp_client_update_observer_remove(client);
1182
1183 NECP_CLIENT_LOCK(client);
1184
1185 // Free route
1186 NECP_CLIENT_ROUTE_LOCK(client);
1187 if (client->current_route != NULL) {
1188 rtfree(client->current_route);
1189 client->current_route = NULL;
1190 }
1191 NECP_CLIENT_ROUTE_UNLOCK(client);
1192
1193 // Remove flow assignments
1194 struct necp_client_flow_registration *flow_registration = NULL;
1195 struct necp_client_flow_registration *temp_flow_registration = NULL;
1196 RB_FOREACH_SAFE(flow_registration, _necp_client_flow_tree, &client->flow_registrations, temp_flow_registration) {
1197 necp_destroy_client_flow_registration(client, flow_registration, pid, abort);
1198 }
1199
cb323159 1200
39037602
A
1201 // Remove agent assertions
1202 struct necp_client_assertion *search_assertion = NULL;
1203 struct necp_client_assertion *temp_assertion = NULL;
1204 LIST_FOREACH_SAFE(search_assertion, &client->assertion_list, assertion_chain, temp_assertion) {
d9a64523 1205 int netagent_error = netagent_client_message(search_assertion->asserted_netagent, client->client_id, pid,
0a7de745 1206 client->agent_handle, NETAGENT_MESSAGE_TYPE_CLIENT_UNASSERT);
39037602 1207 if (netagent_error != 0) {
5ba3f43e 1208 NECPLOG((netagent_error == ENOENT ? LOG_DEBUG : LOG_ERR),
0a7de745 1209 "necp_client_remove unassert agent error (%d)", netagent_error);
39037602
A
1210 }
1211 LIST_REMOVE(search_assertion, assertion_chain);
1212 FREE(search_assertion, M_NECP);
1213 }
39037602 1214
5ba3f43e
A
1215 if (!necp_client_release_locked(client)) {
1216 NECP_CLIENT_UNLOCK(client);
1217 }
1218
1219 OSDecrementAtomic(&necp_client_count);
39037602
A
1220}
1221
1222static int
1223necpop_close(struct fileglob *fg, vfs_context_t ctx)
1224{
5ba3f43e 1225#pragma unused(ctx)
39037602
A
1226 struct necp_fd_data *fd_data = NULL;
1227 int error = 0;
1228
1229 fd_data = (struct necp_fd_data *)fg->fg_data;
1230 fg->fg_data = NULL;
1231
1232 if (fd_data != NULL) {
5ba3f43e
A
1233 struct _necp_client_tree clients_to_close;
1234 RB_INIT(&clients_to_close);
1235
1236 // Remove from list quickly
1237 if (fd_data->flags & NECP_OPEN_FLAG_PUSH_OBSERVER) {
1238 NECP_OBSERVER_LIST_LOCK_EXCLUSIVE();
1239 LIST_REMOVE(fd_data, chain);
1240 NECP_OBSERVER_LIST_UNLOCK();
1241 } else {
1242 NECP_FD_LIST_LOCK_EXCLUSIVE();
1243 LIST_REMOVE(fd_data, chain);
1244 NECP_FD_LIST_UNLOCK();
1245 }
39037602 1246
5ba3f43e
A
1247 NECP_FD_LOCK(fd_data);
1248 pid_t pid = fd_data->proc_pid;
d9a64523
A
1249
1250 struct necp_client_flow_registration *flow_registration = NULL;
1251 struct necp_client_flow_registration *temp_flow_registration = NULL;
1252 RB_FOREACH_SAFE(flow_registration, _necp_fd_flow_tree, &fd_data->flows, temp_flow_registration) {
1253 NECP_FLOW_TREE_LOCK_EXCLUSIVE();
1254 RB_REMOVE(_necp_client_flow_global_tree, &necp_client_flow_global_tree, flow_registration);
1255 NECP_FLOW_TREE_UNLOCK();
1256 RB_REMOVE(_necp_fd_flow_tree, &fd_data->flows, flow_registration);
1257 }
1258
39037602
A
1259 struct necp_client *client = NULL;
1260 struct necp_client *temp_client = NULL;
5ba3f43e
A
1261 RB_FOREACH_SAFE(client, _necp_client_tree, &fd_data->clients, temp_client) {
1262 NECP_CLIENT_TREE_LOCK_EXCLUSIVE();
1263 RB_REMOVE(_necp_client_global_tree, &necp_client_global_tree, client);
1264 NECP_CLIENT_TREE_UNLOCK();
1265 RB_REMOVE(_necp_client_tree, &fd_data->clients, client);
1266 RB_INSERT(_necp_client_tree, &clients_to_close, client);
39037602 1267 }
5ba3f43e
A
1268
1269 struct necp_client_update *client_update = NULL;
1270 struct necp_client_update *temp_update = NULL;
1271 TAILQ_FOREACH_SAFE(client_update, &fd_data->update_list, chain, temp_update) {
1272 // Flush pending updates
1273 TAILQ_REMOVE(&fd_data->update_list, client_update, chain);
1274 FREE(client_update, M_NECP);
1275 }
1276 fd_data->update_count = 0;
1277
1278
1279 NECP_FD_UNLOCK(fd_data);
39037602
A
1280
1281 selthreadclear(&fd_data->si);
1282
1283 lck_mtx_destroy(&fd_data->fd_lock, necp_fd_mtx_grp);
1284
5ba3f43e
A
1285 if (fd_data->flags & NECP_OPEN_FLAG_PUSH_OBSERVER) {
1286 OSDecrementAtomic(&necp_observer_fd_count);
1287 } else {
1288 OSDecrementAtomic(&necp_client_fd_count);
1289 }
39037602 1290
5ba3f43e 1291 zfree(necp_client_fd_zone, fd_data);
39037602 1292 fd_data = NULL;
5ba3f43e
A
1293
1294 RB_FOREACH_SAFE(client, _necp_client_tree, &clients_to_close, temp_client) {
1295 RB_REMOVE(_necp_client_tree, &clients_to_close, client);
1296 necp_destroy_client(client, pid, true);
1297 }
39037602
A
1298 }
1299
0a7de745 1300 return error;
39037602
A
1301}
1302
1303/// NECP client utilities
1304
5ba3f43e
A
1305static inline bool
1306necp_address_is_wildcard(const union necp_sockaddr_union * const addr)
1307{
0a7de745
A
1308 return (addr->sa.sa_family == AF_INET && addr->sin.sin_addr.s_addr == INADDR_ANY) ||
1309 (addr->sa.sa_family == AF_INET6 && IN6_IS_ADDR_UNSPECIFIED(&addr->sin6.sin6_addr));
5ba3f43e
A
1310}
1311
39037602
A
1312static int
1313necp_find_fd_data(int fd, struct necp_fd_data **fd_data)
1314{
1315 proc_t p = current_proc();
1316 struct fileproc *fp = NULL;
1317 int error = 0;
1318
1319 proc_fdlock_spin(p);
1320 if ((error = fp_lookup(p, fd, &fp, 1)) != 0) {
1321 goto done;
1322 }
1323 if (fp->f_fglob->fg_ops->fo_type != DTYPE_NETPOLICY) {
1324 fp_drop(p, fd, fp, 1);
1325 error = ENODEV;
1326 goto done;
1327 }
1328 *fd_data = (struct necp_fd_data *)fp->f_fglob->fg_data;
1329
d9a64523
A
1330 if ((*fd_data)->necp_fd_type != necp_fd_type_client) {
1331 // Not a client fd, ignore
0a7de745 1332 fp_drop(p, fd, fp, 1);
d9a64523
A
1333 error = EINVAL;
1334 goto done;
1335 }
1336
39037602
A
1337done:
1338 proc_fdunlock(p);
0a7de745 1339 return error;
39037602
A
1340}
1341
5ba3f43e 1342
d9a64523
A
1343static struct necp_client_flow *
1344necp_client_add_interface_flow(struct necp_client_flow_registration *flow_registration,
0a7de745 1345 uint32_t interface_index)
5ba3f43e 1346{
a39ff7e2 1347 struct necp_client_flow *new_flow = mcache_alloc(necp_flow_cache, MCR_SLEEP);
5ba3f43e
A
1348 if (new_flow == NULL) {
1349 NECPLOG0(LOG_ERR, "Failed to allocate interface flow");
d9a64523 1350 return NULL;
5ba3f43e
A
1351 }
1352
1353 memset(new_flow, 0, sizeof(*new_flow));
1354
1355 // Neither nexus nor socket
1356 new_flow->interface_index = interface_index;
d9a64523
A
1357 new_flow->u.socket_handle = flow_registration->interface_handle;
1358 new_flow->u.cb = flow_registration->interface_cb;
5ba3f43e
A
1359
1360 OSIncrementAtomic(&necp_if_flow_count);
1361
d9a64523
A
1362 LIST_INSERT_HEAD(&flow_registration->flow_list, new_flow, flow_chain);
1363
1364 return new_flow;
5ba3f43e
A
1365}
1366
d9a64523
A
1367static struct necp_client_flow *
1368necp_client_add_interface_flow_if_needed(struct necp_client *client,
0a7de745
A
1369 struct necp_client_flow_registration *flow_registration,
1370 uint32_t interface_index)
5ba3f43e
A
1371{
1372 if (!client->allow_multiple_flows ||
0a7de745 1373 interface_index == IFSCOPE_NONE) {
5ba3f43e 1374 // Interface not set, or client not allowed to use this mode
d9a64523 1375 return NULL;
5ba3f43e
A
1376 }
1377
1378 struct necp_client_flow *flow = NULL;
d9a64523 1379 LIST_FOREACH(flow, &flow_registration->flow_list, flow_chain) {
5ba3f43e
A
1380 if (!flow->nexus && !flow->socket && flow->interface_index == interface_index) {
1381 // Already have the flow
1382 flow->invalid = FALSE;
d9a64523
A
1383 flow->u.socket_handle = flow_registration->interface_handle;
1384 flow->u.cb = flow_registration->interface_cb;
1385 return NULL;
1386 }
1387 }
1388 return necp_client_add_interface_flow(flow_registration, interface_index);
1389}
1390
1391static void
1392necp_client_add_interface_option_if_needed(struct necp_client *client,
0a7de745
A
1393 uint32_t interface_index,
1394 uint32_t interface_generation,
1395 uuid_t *nexus_agent)
d9a64523
A
1396{
1397 if (interface_index == IFSCOPE_NONE ||
0a7de745 1398 (client->interface_option_count != 0 && !client->allow_multiple_flows)) {
d9a64523
A
1399 // Interface not set, or client not allowed to use this mode
1400 return;
1401 }
1402
1403 if (client->interface_option_count >= NECP_CLIENT_MAX_INTERFACE_OPTIONS) {
1404 // Cannot take any more interface options
1405 return;
1406 }
5ba3f43e 1407
d9a64523
A
1408 // Check if already present
1409 for (u_int32_t option_i = 0; option_i < client->interface_option_count; option_i++) {
1410 if (option_i < NECP_CLIENT_INTERFACE_OPTION_STATIC_COUNT) {
1411 struct necp_client_interface_option *option = &client->interface_options[option_i];
1412 if (option->interface_index == interface_index) {
1413 if (nexus_agent == NULL) {
1414 return;
1415 }
1416 if (uuid_compare(option->nexus_agent, *nexus_agent) == 0) {
1417 return;
1418 }
1419 if (uuid_is_null(option->nexus_agent)) {
1420 uuid_copy(option->nexus_agent, *nexus_agent);
1421 return;
1422 }
1423 // If we get to this point, this is a new nexus flow
1424 }
1425 } else {
1426 struct necp_client_interface_option *option = &client->extra_interface_options[option_i - NECP_CLIENT_INTERFACE_OPTION_STATIC_COUNT];
1427 if (option->interface_index == interface_index) {
1428 if (nexus_agent == NULL) {
1429 return;
1430 }
1431 if (uuid_compare(option->nexus_agent, *nexus_agent) == 0) {
1432 return;
1433 }
1434 if (uuid_is_null(option->nexus_agent)) {
1435 uuid_copy(option->nexus_agent, *nexus_agent);
1436 return;
1437 }
1438 // If we get to this point, this is a new nexus flow
1439 }
5ba3f43e
A
1440 }
1441 }
1442
d9a64523
A
1443 // Add a new entry
1444 if (client->interface_option_count < NECP_CLIENT_INTERFACE_OPTION_STATIC_COUNT) {
1445 // Add to static
1446 struct necp_client_interface_option *option = &client->interface_options[client->interface_option_count];
1447 option->interface_index = interface_index;
1448 option->interface_generation = interface_generation;
1449 if (nexus_agent != NULL) {
1450 uuid_copy(option->nexus_agent, *nexus_agent);
cb323159
A
1451 } else {
1452 uuid_clear(option->nexus_agent);
d9a64523
A
1453 }
1454 client->interface_option_count++;
1455 } else {
1456 // Add to extra
1457 if (client->extra_interface_options == NULL) {
1458 client->extra_interface_options = _MALLOC(sizeof(struct necp_client_interface_option) * NECP_CLIENT_INTERFACE_OPTION_EXTRA_COUNT, M_NECP, M_WAITOK | M_ZERO);
1459 }
1460 if (client->extra_interface_options != NULL) {
1461 struct necp_client_interface_option *option = &client->extra_interface_options[client->interface_option_count - NECP_CLIENT_INTERFACE_OPTION_STATIC_COUNT];
1462 option->interface_index = interface_index;
1463 option->interface_generation = interface_generation;
1464 if (nexus_agent != NULL) {
1465 uuid_copy(option->nexus_agent, *nexus_agent);
cb323159
A
1466 } else {
1467 uuid_clear(option->nexus_agent);
d9a64523
A
1468 }
1469 client->interface_option_count++;
1470 }
1471 }
5ba3f43e
A
1472}
1473
1474static bool
1475necp_client_flow_is_viable(proc_t proc, struct necp_client *client,
0a7de745 1476 struct necp_client_flow *flow)
5ba3f43e
A
1477{
1478 struct necp_aggregate_result result;
1479 bool ignore_address = (client->allow_multiple_flows && !flow->nexus && !flow->socket);
1480
1481 flow->necp_flow_flags = 0;
1482 int error = necp_application_find_policy_match_internal(proc, client->parameters,
0a7de745 1483 (u_int32_t)client->parameters_length,
cb323159 1484 &result, &flow->necp_flow_flags, NULL,
0a7de745 1485 flow->interface_index,
cb323159 1486 &flow->local_addr, &flow->remote_addr, NULL, NULL,
ea3f0419 1487 NULL, ignore_address, true, NULL);
0a7de745 1488
94ff46dc
A
1489 // Check for blocking agents
1490 for (int i = 0; i < NECP_MAX_NETAGENTS; i++) {
1491 if (uuid_is_null(result.netagents[i])) {
1492 // Passed end of valid agents
1493 break;
1494 }
1495
1496 u_int32_t flags = netagent_get_flags(result.netagents[i]);
1497 if ((flags & NETAGENT_FLAG_REGISTERED) &&
1498 !(flags & NETAGENT_FLAG_VOLUNTARY) &&
1499 !(flags & NETAGENT_FLAG_ACTIVE) &&
1500 !(flags & NETAGENT_FLAG_SPECIFIC_USE_ONLY)) {
1501 // A required agent is not active, cause the flow to be marked non-viable
1502 return false;
1503 }
1504 }
1505
0a7de745
A
1506 return error == 0 &&
1507 result.routed_interface_index != IFSCOPE_NONE &&
1508 result.routing_result != NECP_KERNEL_POLICY_RESULT_DROP;
5ba3f43e
A
1509}
1510
d9a64523
A
1511static void
1512necp_flow_add_interface_flows(proc_t proc,
0a7de745
A
1513 struct necp_client *client,
1514 struct necp_client_flow_registration *flow_registration,
1515 bool send_initial)
d9a64523
A
1516{
1517 // Traverse all interfaces and add a tracking flow if needed
1518 for (u_int32_t option_i = 0; option_i < client->interface_option_count; option_i++) {
1519 if (option_i < NECP_CLIENT_INTERFACE_OPTION_STATIC_COUNT) {
1520 struct necp_client_interface_option *option = &client->interface_options[option_i];
1521 struct necp_client_flow *flow = necp_client_add_interface_flow_if_needed(client, flow_registration, option->interface_index);
1522 if (flow != NULL && send_initial) {
1523 flow->viable = necp_client_flow_is_viable(proc, client, flow);
1524 if (flow->viable && flow->u.cb) {
1525 bool viable = flow->viable;
1526 flow->u.cb(flow_registration->interface_handle, NECP_CLIENT_CBACTION_INITIAL, flow->interface_index, flow->necp_flow_flags, &viable);
1527 flow->viable = viable;
1528 }
1529 }
1530 } else {
1531 struct necp_client_interface_option *option = &client->extra_interface_options[option_i - NECP_CLIENT_INTERFACE_OPTION_STATIC_COUNT];
1532 struct necp_client_flow *flow = necp_client_add_interface_flow_if_needed(client, flow_registration, option->interface_index);
1533 if (flow != NULL && send_initial) {
1534 flow->viable = necp_client_flow_is_viable(proc, client, flow);
1535 if (flow->viable && flow->u.cb) {
1536 bool viable = flow->viable;
1537 flow->u.cb(flow_registration->interface_handle, NECP_CLIENT_CBACTION_INITIAL, flow->interface_index, flow->necp_flow_flags, &viable);
1538 flow->viable = viable;
1539 }
1540 }
1541 }
1542 }
1543}
1544
5ba3f43e 1545static bool
a39ff7e2 1546necp_client_update_flows(proc_t proc,
0a7de745
A
1547 struct necp_client *client,
1548 struct _necp_flow_defunct_list *defunct_list)
5ba3f43e 1549{
a39ff7e2
A
1550 NECP_CLIENT_ASSERT_LOCKED(client);
1551
5ba3f43e
A
1552 bool client_updated = FALSE;
1553 struct necp_client_flow *flow = NULL;
1554 struct necp_client_flow *temp_flow = NULL;
d9a64523
A
1555 struct necp_client_flow_registration *flow_registration = NULL;
1556 RB_FOREACH(flow_registration, _necp_client_flow_tree, &client->flow_registrations) {
1557 if (flow_registration->interface_cb != NULL) {
1558 // Add any interface flows that are not already tracked
1559 necp_flow_add_interface_flows(proc, client, flow_registration, false);
5ba3f43e
A
1560 }
1561
d9a64523
A
1562 LIST_FOREACH_SAFE(flow, &flow_registration->flow_list, flow_chain, temp_flow) {
1563 // Check policy result for flow
1564 int old_flags = flow->necp_flow_flags;
1565 bool viable = necp_client_flow_is_viable(proc, client, flow);
5ba3f43e 1566
d9a64523 1567 // TODO: Defunct nexus flows that are blocked by policy
5ba3f43e 1568
d9a64523
A
1569 if (flow->viable != viable) {
1570 flow->viable = viable;
1571 client_updated = TRUE;
1572 }
1573
1574 if ((old_flags & NECP_CLIENT_RESULT_FLAG_FORCE_UPDATE) !=
0a7de745 1575 (flow->necp_flow_flags & NECP_CLIENT_RESULT_FLAG_FORCE_UPDATE)) {
d9a64523 1576 client_updated = TRUE;
5ba3f43e 1577 }
5ba3f43e 1578
d9a64523
A
1579 if (flow->viable && client_updated && (flow->socket || (!flow->socket && !flow->nexus)) && flow->u.cb) {
1580 bool flow_viable = flow->viable;
cb323159 1581 flow->u.cb(flow->u.socket_handle, NECP_CLIENT_CBACTION_VIABLE, flow->interface_index, flow->necp_flow_flags, &flow_viable);
d9a64523
A
1582 flow->viable = flow_viable;
1583 }
5ba3f43e 1584
d9a64523
A
1585 if (!flow->viable || flow->invalid) {
1586 if (client_updated && (flow->socket || (!flow->socket && !flow->nexus)) && flow->u.cb) {
1587 bool flow_viable = flow->viable;
cb323159 1588 flow->u.cb(flow->u.socket_handle, NECP_CLIENT_CBACTION_NONVIABLE, flow->interface_index, flow->necp_flow_flags, &flow_viable);
d9a64523 1589 flow->viable = flow_viable;
5ba3f43e 1590 }
d9a64523
A
1591 // The callback might change the viable-flag of the
1592 // flow depending on its policy. Thus, we need to
1593 // check the flags again after the callback.
1594 }
1595
1596 (void)defunct_list;
1597
1598 // Handle flows that no longer match
1599 if (!flow->viable || flow->invalid) {
1600 // Drop them as long as they aren't assigned data
1601 if (!flow->nexus && !flow->assigned) {
1602 if (flow->assigned_results != NULL) {
1603 FREE(flow->assigned_results, M_NETAGENT);
1604 flow->assigned_results = NULL;
1605 client_updated = TRUE;
1606 }
1607 LIST_REMOVE(flow, flow_chain);
1608 if (flow->socket) {
1609 OSDecrementAtomic(&necp_socket_flow_count);
1610 } else {
1611 OSDecrementAtomic(&necp_if_flow_count);
1612 }
1613 mcache_free(necp_flow_cache, flow);
5ba3f43e 1614 }
5ba3f43e
A
1615 }
1616 }
1617 }
1618
0a7de745 1619 return client_updated;
5ba3f43e
A
1620}
1621
1622static void
1623necp_client_mark_all_nonsocket_flows_as_invalid(struct necp_client *client)
1624{
d9a64523 1625 struct necp_client_flow_registration *flow_registration = NULL;
5ba3f43e 1626 struct necp_client_flow *flow = NULL;
d9a64523
A
1627 RB_FOREACH(flow_registration, _necp_client_flow_tree, &client->flow_registrations) {
1628 LIST_FOREACH(flow, &flow_registration->flow_list, flow_chain) {
1629 if (!flow->socket) { // Socket flows are not marked as invalid
1630 flow->invalid = TRUE;
1631 }
5ba3f43e
A
1632 }
1633 }
d9a64523
A
1634
1635 // Reset option count every update
1636 client->interface_option_count = 0;
5ba3f43e
A
1637}
1638
ea3f0419
A
1639static inline bool
1640necp_netagent_is_required(const struct necp_client_parsed_parameters *parameters,
1641 uuid_t *netagent_uuid)
1642{
1643 // Specific use agents only apply when required
1644 bool required = false;
1645 if (parameters != NULL) {
1646 // Check required agent UUIDs
1647 for (int i = 0; i < NECP_MAX_AGENT_PARAMETERS; i++) {
1648 if (uuid_is_null(parameters->required_netagents[i])) {
1649 break;
1650 }
1651 if (uuid_compare(parameters->required_netagents[i], *netagent_uuid) == 0) {
1652 required = true;
1653 break;
1654 }
1655 }
1656
1657 if (!required) {
1658 // Check required agent types
1659 bool fetched_type = false;
1660 char netagent_domain[NETAGENT_DOMAINSIZE];
1661 char netagent_type[NETAGENT_TYPESIZE];
1662 memset(&netagent_domain, 0, NETAGENT_DOMAINSIZE);
1663 memset(&netagent_type, 0, NETAGENT_TYPESIZE);
1664
1665 for (int i = 0; i < NECP_MAX_AGENT_PARAMETERS; i++) {
1666 if (strlen(parameters->required_netagent_types[i].netagent_domain) == 0 ||
1667 strlen(parameters->required_netagent_types[i].netagent_type) == 0) {
1668 break;
1669 }
1670
1671 if (!fetched_type) {
1672 if (netagent_get_agent_domain_and_type(*netagent_uuid, netagent_domain, netagent_type)) {
1673 fetched_type = TRUE;
1674 } else {
1675 break;
1676 }
1677 }
1678
1679 if ((strlen(parameters->required_netagent_types[i].netagent_domain) == 0 ||
1680 strncmp(netagent_domain, parameters->required_netagent_types[i].netagent_domain, NETAGENT_DOMAINSIZE) == 0) &&
1681 (strlen(parameters->required_netagent_types[i].netagent_type) == 0 ||
1682 strncmp(netagent_type, parameters->required_netagent_types[i].netagent_type, NETAGENT_TYPESIZE) == 0)) {
1683 required = true;
1684 break;
1685 }
1686 }
1687 }
1688 }
1689
1690 return required;
1691}
1692
5ba3f43e 1693static bool
d9a64523 1694necp_netagent_applies_to_client(struct necp_client *client,
0a7de745
A
1695 const struct necp_client_parsed_parameters *parameters,
1696 uuid_t *netagent_uuid, bool allow_nexus,
1697 uint32_t interface_index, uint32_t interface_generation)
5ba3f43e 1698{
d9a64523 1699#pragma unused(interface_index, interface_generation)
5ba3f43e 1700 bool applies = FALSE;
d9a64523 1701 u_int32_t flags = netagent_get_flags(*netagent_uuid);
5ba3f43e
A
1702 if (!(flags & NETAGENT_FLAG_REGISTERED)) {
1703 // Unregistered agents never apply
0a7de745 1704 return applies;
5ba3f43e
A
1705 }
1706
cb323159
A
1707 const bool is_nexus_agent = ((flags & NETAGENT_FLAG_NEXUS_PROVIDER) ||
1708 (flags & NETAGENT_FLAG_NEXUS_LISTENER) ||
1709 (flags & NETAGENT_FLAG_CUSTOM_ETHER_NEXUS) ||
1710 (flags & NETAGENT_FLAG_CUSTOM_IP_NEXUS) ||
1711 (flags & NETAGENT_FLAG_INTERPOSE_NEXUS));
1712 if (is_nexus_agent) {
1713 if (!allow_nexus) {
1714 // Hide nexus providers unless allowed
1715 // Direct interfaces and direct policies are allowed to use a nexus
1716 // Delegate interfaces or re-scoped interfaces are not allowed
1717 return applies;
1718 }
1719
1720 if ((parameters->flags & NECP_CLIENT_PARAMETER_FLAG_CUSTOM_ETHER) &&
1721 !(flags & NETAGENT_FLAG_CUSTOM_ETHER_NEXUS)) {
1722 // Client requested a custom ether nexus, but this nexus isn't one
1723 return applies;
1724 }
1725
1726 if ((parameters->flags & NECP_CLIENT_PARAMETER_FLAG_CUSTOM_IP) &&
1727 !(flags & NETAGENT_FLAG_CUSTOM_IP_NEXUS)) {
1728 // Client requested a custom IP nexus, but this nexus isn't one
1729 return applies;
1730 }
1731
1732 if ((parameters->flags & NECP_CLIENT_PARAMETER_FLAG_INTERPOSE) &&
1733 !(flags & NETAGENT_FLAG_INTERPOSE_NEXUS)) {
1734 // Client requested an interpose nexus, but this nexus isn't one
1735 return applies;
1736 }
1737
1738 if (!(parameters->flags & NECP_CLIENT_PARAMETER_FLAG_CUSTOM_ETHER) &&
1739 !(parameters->flags & NECP_CLIENT_PARAMETER_FLAG_CUSTOM_IP) &&
1740 !(parameters->flags & NECP_CLIENT_PARAMETER_FLAG_INTERPOSE) &&
1741 !(flags & NETAGENT_FLAG_NEXUS_PROVIDER)) {
1742 // Client requested default parameters, but this nexus isn't generic
1743 return applies;
1744 }
5ba3f43e 1745 }
39037602 1746
d9a64523
A
1747 if (uuid_compare(client->failed_trigger_agent.netagent_uuid, *netagent_uuid) == 0) {
1748 if (client->failed_trigger_agent.generation == netagent_get_generation(*netagent_uuid)) {
1749 // If this agent was triggered, and failed, and hasn't changed, keep hiding it
0a7de745 1750 return applies;
d9a64523
A
1751 } else {
1752 // Mismatch generation, clear out old trigger
1753 uuid_clear(client->failed_trigger_agent.netagent_uuid);
1754 client->failed_trigger_agent.generation = 0;
1755 }
1756 }
1757
39037602
A
1758 if (flags & NETAGENT_FLAG_SPECIFIC_USE_ONLY) {
1759 // Specific use agents only apply when required
ea3f0419 1760 applies = necp_netagent_is_required(parameters, netagent_uuid);
39037602
A
1761 } else {
1762 applies = TRUE;
1763 }
1764
39037602 1765
0a7de745 1766 return applies;
39037602
A
1767}
1768
5ba3f43e 1769static void
d9a64523 1770necp_client_add_agent_interface_options(struct necp_client *client,
0a7de745
A
1771 const struct necp_client_parsed_parameters *parsed_parameters,
1772 ifnet_t ifp)
5ba3f43e
A
1773{
1774 if (ifp != NULL && ifp->if_agentids != NULL) {
1775 for (u_int32_t i = 0; i < ifp->if_agentcount; i++) {
1776 if (uuid_is_null(ifp->if_agentids[i])) {
1777 continue;
1778 }
5ba3f43e 1779 // Relies on the side effect that nexus agents that apply will create flows
d9a64523 1780 (void)necp_netagent_applies_to_client(client, parsed_parameters, &ifp->if_agentids[i], TRUE,
0a7de745 1781 ifp->if_index, ifnet_get_generation(ifp));
5ba3f43e
A
1782 }
1783 }
1784}
1785
ea3f0419
A
1786static void
1787necp_client_add_browse_interface_options(struct necp_client *client,
1788 const struct necp_client_parsed_parameters *parsed_parameters,
1789 ifnet_t ifp)
1790{
1791 if (ifp != NULL && ifp->if_agentids != NULL) {
1792 for (u_int32_t i = 0; i < ifp->if_agentcount; i++) {
1793 if (uuid_is_null(ifp->if_agentids[i])) {
1794 continue;
1795 }
1796
1797 u_int32_t flags = netagent_get_flags(ifp->if_agentids[i]);
1798 if ((flags & NETAGENT_FLAG_REGISTERED) &&
1799 (flags & NETAGENT_FLAG_ACTIVE) &&
1800 (flags & NETAGENT_FLAG_SUPPORTS_BROWSE) &&
1801 (!(flags & NETAGENT_FLAG_SPECIFIC_USE_ONLY) ||
1802 necp_netagent_is_required(parsed_parameters, &ifp->if_agentids[i]))) {
1803 necp_client_add_interface_option_if_needed(client, ifp->if_index, ifnet_get_generation(ifp), &ifp->if_agentids[i]);
1804
1805 // Finding one is enough
1806 break;
1807 }
1808 }
1809 }
1810}
1811
5ba3f43e
A
1812static inline bool
1813necp_client_address_is_valid(struct sockaddr *address)
1814{
1815 if (address->sa_family == AF_INET) {
0a7de745 1816 return address->sa_len == sizeof(struct sockaddr_in);
5ba3f43e 1817 } else if (address->sa_family == AF_INET6) {
0a7de745 1818 return address->sa_len == sizeof(struct sockaddr_in6);
5ba3f43e 1819 } else {
0a7de745 1820 return FALSE;
5ba3f43e
A
1821 }
1822}
1823
cb323159
A
1824static inline bool
1825necp_client_endpoint_is_unspecified(struct necp_client_endpoint *endpoint)
1826{
1827 if (necp_client_address_is_valid(&endpoint->u.sa)) {
1828 if (endpoint->u.sa.sa_family == AF_INET) {
1829 return endpoint->u.sin.sin_addr.s_addr == INADDR_ANY;
1830 } else if (endpoint->u.sa.sa_family == AF_INET6) {
1831 return IN6_IS_ADDR_UNSPECIFIED(&endpoint->u.sin6.sin6_addr);
1832 } else {
1833 return TRUE;
1834 }
1835 } else {
1836 return TRUE;
1837 }
1838}
1839
1840
39037602
A
1841static int
1842necp_client_parse_parameters(u_int8_t *parameters,
0a7de745
A
1843 u_int32_t parameters_size,
1844 struct necp_client_parsed_parameters *parsed_parameters)
39037602
A
1845{
1846 int error = 0;
1847 size_t offset = 0;
1848
1849 u_int32_t num_prohibited_interfaces = 0;
39037602
A
1850 u_int32_t num_prohibited_interface_types = 0;
1851 u_int32_t num_required_agents = 0;
1852 u_int32_t num_prohibited_agents = 0;
1853 u_int32_t num_preferred_agents = 0;
d9a64523 1854 u_int32_t num_avoided_agents = 0;
39037602
A
1855 u_int32_t num_required_agent_types = 0;
1856 u_int32_t num_prohibited_agent_types = 0;
1857 u_int32_t num_preferred_agent_types = 0;
d9a64523 1858 u_int32_t num_avoided_agent_types = 0;
cb323159
A
1859 u_int8_t *resolver_tag = NULL;
1860 u_int32_t resolver_tag_length = 0;
1861 u_int8_t *client_hostname = NULL;
1862 u_int32_t hostname_length = 0;
1863 uuid_t parent_id = {};
39037602
A
1864
1865 if (parsed_parameters == NULL) {
0a7de745 1866 return EINVAL;
39037602
A
1867 }
1868
1869 memset(parsed_parameters, 0, sizeof(struct necp_client_parsed_parameters));
1870
5ba3f43e 1871 while ((offset + sizeof(struct necp_tlv_header)) <= parameters_size) {
39037602
A
1872 u_int8_t type = necp_buffer_get_tlv_type(parameters, offset);
1873 u_int32_t length = necp_buffer_get_tlv_length(parameters, offset);
1874
5ba3f43e 1875 if (length > (parameters_size - (offset + sizeof(struct necp_tlv_header)))) {
813fb2f6
A
1876 // If the length is larger than what can fit in the remaining parameters size, bail
1877 NECPLOG(LOG_ERR, "Invalid TLV length (%u)", length);
1878 break;
1879 }
1880
1881 if (length > 0) {
39037602
A
1882 u_int8_t *value = necp_buffer_get_tlv_value(parameters, offset, NULL);
1883 if (value != NULL) {
1884 switch (type) {
0a7de745
A
1885 case NECP_CLIENT_PARAMETER_BOUND_INTERFACE: {
1886 if (length <= IFXNAMSIZ && length > 0) {
1887 ifnet_t bound_interface = NULL;
1888 char interface_name[IFXNAMSIZ];
1889 memcpy(interface_name, value, length);
1890 interface_name[length - 1] = 0; // Make sure the string is NULL terminated
1891 if (ifnet_find_by_name(interface_name, &bound_interface) == 0) {
1892 parsed_parameters->required_interface_index = bound_interface->if_index;
1893 parsed_parameters->valid_fields |= NECP_PARSED_PARAMETERS_FIELD_REQUIRED_IF;
1894 ifnet_release(bound_interface);
39037602 1895 }
39037602 1896 }
0a7de745
A
1897 break;
1898 }
1899 case NECP_CLIENT_PARAMETER_LOCAL_ADDRESS: {
1900 if (length >= sizeof(struct necp_policy_condition_addr)) {
1901 struct necp_policy_condition_addr *address_struct = (struct necp_policy_condition_addr *)(void *)value;
1902 if (necp_client_address_is_valid(&address_struct->address.sa)) {
1903 memcpy(&parsed_parameters->local_addr, &address_struct->address, sizeof(address_struct->address));
1904 if (!necp_address_is_wildcard(&parsed_parameters->local_addr)) {
1905 parsed_parameters->valid_fields |= NECP_PARSED_PARAMETERS_FIELD_LOCAL_ADDR;
39037602 1906 }
0a7de745
A
1907 if ((parsed_parameters->local_addr.sa.sa_family == AF_INET && parsed_parameters->local_addr.sin.sin_port) ||
1908 (parsed_parameters->local_addr.sa.sa_family == AF_INET6 && parsed_parameters->local_addr.sin6.sin6_port)) {
1909 parsed_parameters->valid_fields |= NECP_PARSED_PARAMETERS_FIELD_LOCAL_PORT;
39037602
A
1910 }
1911 }
39037602 1912 }
0a7de745
A
1913 break;
1914 }
1915 case NECP_CLIENT_PARAMETER_LOCAL_ENDPOINT: {
1916 if (length >= sizeof(struct necp_client_endpoint)) {
1917 struct necp_client_endpoint *endpoint = (struct necp_client_endpoint *)(void *)value;
1918 if (necp_client_address_is_valid(&endpoint->u.sa)) {
1919 memcpy(&parsed_parameters->local_addr, &endpoint->u.sa, sizeof(union necp_sockaddr_union));
1920 if (!necp_address_is_wildcard(&parsed_parameters->local_addr)) {
1921 parsed_parameters->valid_fields |= NECP_PARSED_PARAMETERS_FIELD_LOCAL_ADDR;
39037602 1922 }
0a7de745
A
1923 if ((parsed_parameters->local_addr.sa.sa_family == AF_INET && parsed_parameters->local_addr.sin.sin_port) ||
1924 (parsed_parameters->local_addr.sa.sa_family == AF_INET6 && parsed_parameters->local_addr.sin6.sin6_port)) {
1925 parsed_parameters->valid_fields |= NECP_PARSED_PARAMETERS_FIELD_LOCAL_PORT;
39037602
A
1926 }
1927 }
39037602 1928 }
0a7de745
A
1929 break;
1930 }
1931 case NECP_CLIENT_PARAMETER_REMOTE_ADDRESS: {
1932 if (length >= sizeof(struct necp_policy_condition_addr)) {
1933 struct necp_policy_condition_addr *address_struct = (struct necp_policy_condition_addr *)(void *)value;
1934 if (necp_client_address_is_valid(&address_struct->address.sa)) {
1935 memcpy(&parsed_parameters->remote_addr, &address_struct->address, sizeof(address_struct->address));
1936 parsed_parameters->valid_fields |= NECP_PARSED_PARAMETERS_FIELD_REMOTE_ADDR;
39037602 1937 }
39037602 1938 }
0a7de745
A
1939 break;
1940 }
1941 case NECP_CLIENT_PARAMETER_REMOTE_ENDPOINT: {
1942 if (length >= sizeof(struct necp_client_endpoint)) {
1943 struct necp_client_endpoint *endpoint = (struct necp_client_endpoint *)(void *)value;
1944 if (necp_client_address_is_valid(&endpoint->u.sa)) {
1945 memcpy(&parsed_parameters->remote_addr, &endpoint->u.sa, sizeof(union necp_sockaddr_union));
1946 parsed_parameters->valid_fields |= NECP_PARSED_PARAMETERS_FIELD_REMOTE_ADDR;
39037602 1947 }
39037602 1948 }
0a7de745
A
1949 break;
1950 }
1951 case NECP_CLIENT_PARAMETER_PROHIBIT_INTERFACE: {
cb323159 1952 if (num_prohibited_interfaces >= NECP_MAX_INTERFACE_PARAMETERS) {
39037602
A
1953 break;
1954 }
0a7de745
A
1955 if (length <= IFXNAMSIZ && length > 0) {
1956 memcpy(parsed_parameters->prohibited_interfaces[num_prohibited_interfaces], value, length);
1957 parsed_parameters->prohibited_interfaces[num_prohibited_interfaces][length - 1] = 0; // Make sure the string is NULL terminated
1958 num_prohibited_interfaces++;
1959 parsed_parameters->valid_fields |= NECP_PARSED_PARAMETERS_FIELD_PROHIBITED_IF;
39037602 1960 }
0a7de745
A
1961 break;
1962 }
1963 case NECP_CLIENT_PARAMETER_REQUIRE_IF_TYPE: {
1964 if (parsed_parameters->valid_fields & NECP_PARSED_PARAMETERS_FIELD_REQUIRED_IFTYPE) {
39037602
A
1965 break;
1966 }
0a7de745
A
1967 if (length >= sizeof(u_int8_t)) {
1968 memcpy(&parsed_parameters->required_interface_type, value, sizeof(u_int8_t));
1969 if (parsed_parameters->required_interface_type) {
1970 parsed_parameters->valid_fields |= NECP_PARSED_PARAMETERS_FIELD_REQUIRED_IFTYPE;
39037602 1971 }
39037602 1972 }
0a7de745
A
1973 break;
1974 }
1975 case NECP_CLIENT_PARAMETER_PROHIBIT_IF_TYPE: {
cb323159 1976 if (num_prohibited_interface_types >= NECP_MAX_INTERFACE_PARAMETERS) {
d9a64523
A
1977 break;
1978 }
0a7de745
A
1979 if (length >= sizeof(u_int8_t)) {
1980 memcpy(&parsed_parameters->prohibited_interface_types[num_prohibited_interface_types], value, sizeof(u_int8_t));
1981 num_prohibited_interface_types++;
1982 parsed_parameters->valid_fields |= NECP_PARSED_PARAMETERS_FIELD_PROHIBITED_IFTYPE;
39037602 1983 }
0a7de745
A
1984 break;
1985 }
1986 case NECP_CLIENT_PARAMETER_REQUIRE_AGENT: {
cb323159 1987 if (num_required_agents >= NECP_MAX_AGENT_PARAMETERS) {
39037602
A
1988 break;
1989 }
0a7de745
A
1990 if (length >= sizeof(uuid_t)) {
1991 memcpy(&parsed_parameters->required_netagents[num_required_agents], value, sizeof(uuid_t));
1992 num_required_agents++;
1993 parsed_parameters->valid_fields |= NECP_PARSED_PARAMETERS_FIELD_REQUIRED_AGENT;
39037602 1994 }
0a7de745
A
1995 break;
1996 }
1997 case NECP_CLIENT_PARAMETER_PROHIBIT_AGENT: {
cb323159 1998 if (num_prohibited_agents >= NECP_MAX_AGENT_PARAMETERS) {
d9a64523
A
1999 break;
2000 }
0a7de745
A
2001 if (length >= sizeof(uuid_t)) {
2002 memcpy(&parsed_parameters->prohibited_netagents[num_prohibited_agents], value, sizeof(uuid_t));
2003 num_prohibited_agents++;
2004 parsed_parameters->valid_fields |= NECP_PARSED_PARAMETERS_FIELD_PROHIBITED_AGENT;
2005 }
2006 break;
2007 }
2008 case NECP_CLIENT_PARAMETER_PREFER_AGENT: {
cb323159 2009 if (num_preferred_agents >= NECP_MAX_AGENT_PARAMETERS) {
5ba3f43e
A
2010 break;
2011 }
0a7de745
A
2012 if (length >= sizeof(uuid_t)) {
2013 memcpy(&parsed_parameters->preferred_netagents[num_preferred_agents], value, sizeof(uuid_t));
2014 num_preferred_agents++;
2015 parsed_parameters->valid_fields |= NECP_PARSED_PARAMETERS_FIELD_PREFERRED_AGENT;
2016 }
2017 break;
2018 }
2019 case NECP_CLIENT_PARAMETER_AVOID_AGENT: {
cb323159 2020 if (num_avoided_agents >= NECP_MAX_AGENT_PARAMETERS) {
5ba3f43e
A
2021 break;
2022 }
0a7de745
A
2023 if (length >= sizeof(uuid_t)) {
2024 memcpy(&parsed_parameters->avoided_netagents[num_avoided_agents], value, sizeof(uuid_t));
2025 num_avoided_agents++;
2026 parsed_parameters->valid_fields |= NECP_PARSED_PARAMETERS_FIELD_AVOIDED_AGENT;
2027 }
2028 break;
2029 }
2030 case NECP_CLIENT_PARAMETER_REQUIRE_AGENT_TYPE: {
cb323159 2031 if (num_required_agent_types >= NECP_MAX_AGENT_PARAMETERS) {
5ba3f43e
A
2032 break;
2033 }
0a7de745
A
2034 if (length >= sizeof(struct necp_client_parameter_netagent_type)) {
2035 memcpy(&parsed_parameters->required_netagent_types[num_required_agent_types], value, sizeof(struct necp_client_parameter_netagent_type));
2036 num_required_agent_types++;
2037 parsed_parameters->valid_fields |= NECP_PARSED_PARAMETERS_FIELD_REQUIRED_AGENT_TYPE;
2038 }
2039 break;
2040 }
2041 case NECP_CLIENT_PARAMETER_PROHIBIT_AGENT_TYPE: {
cb323159 2042 if (num_prohibited_agent_types >= NECP_MAX_AGENT_PARAMETERS) {
5ba3f43e
A
2043 break;
2044 }
0a7de745
A
2045 if (length >= sizeof(struct necp_client_parameter_netagent_type)) {
2046 memcpy(&parsed_parameters->prohibited_netagent_types[num_prohibited_agent_types], value, sizeof(struct necp_client_parameter_netagent_type));
2047 num_prohibited_agent_types++;
2048 parsed_parameters->valid_fields |= NECP_PARSED_PARAMETERS_FIELD_PROHIBITED_AGENT_TYPE;
2049 }
2050 break;
2051 }
2052 case NECP_CLIENT_PARAMETER_PREFER_AGENT_TYPE: {
cb323159 2053 if (num_preferred_agent_types >= NECP_MAX_AGENT_PARAMETERS) {
5ba3f43e
A
2054 break;
2055 }
0a7de745
A
2056 if (length >= sizeof(struct necp_client_parameter_netagent_type)) {
2057 memcpy(&parsed_parameters->preferred_netagent_types[num_preferred_agent_types], value, sizeof(struct necp_client_parameter_netagent_type));
2058 num_preferred_agent_types++;
2059 parsed_parameters->valid_fields |= NECP_PARSED_PARAMETERS_FIELD_PREFERRED_AGENT_TYPE;
2060 }
2061 break;
2062 }
2063 case NECP_CLIENT_PARAMETER_AVOID_AGENT_TYPE: {
cb323159 2064 if (num_avoided_agent_types >= NECP_MAX_AGENT_PARAMETERS) {
5ba3f43e
A
2065 break;
2066 }
0a7de745
A
2067 if (length >= sizeof(struct necp_client_parameter_netagent_type)) {
2068 memcpy(&parsed_parameters->avoided_netagent_types[num_avoided_agent_types], value, sizeof(struct necp_client_parameter_netagent_type));
2069 num_avoided_agent_types++;
2070 parsed_parameters->valid_fields |= NECP_PARSED_PARAMETERS_FIELD_AVOIDED_AGENT_TYPE;
2071 }
2072 break;
2073 }
2074 case NECP_CLIENT_PARAMETER_FLAGS: {
2075 if (length >= sizeof(u_int32_t)) {
2076 memcpy(&parsed_parameters->flags, value, sizeof(parsed_parameters->flags));
2077 parsed_parameters->valid_fields |= NECP_PARSED_PARAMETERS_FIELD_FLAGS;
2078 }
2079 break;
2080 }
2081 case NECP_CLIENT_PARAMETER_IP_PROTOCOL: {
cb323159
A
2082 if (length == sizeof(u_int16_t)) {
2083 u_int16_t large_ip_protocol = 0;
2084 memcpy(&large_ip_protocol, value, sizeof(large_ip_protocol));
2085 parsed_parameters->ip_protocol = (u_int8_t)large_ip_protocol;
2086 parsed_parameters->valid_fields |= NECP_PARSED_PARAMETERS_FIELD_IP_PROTOCOL;
2087 } else if (length >= sizeof(parsed_parameters->ip_protocol)) {
0a7de745
A
2088 memcpy(&parsed_parameters->ip_protocol, value, sizeof(parsed_parameters->ip_protocol));
2089 parsed_parameters->valid_fields |= NECP_PARSED_PARAMETERS_FIELD_IP_PROTOCOL;
2090 }
2091 break;
2092 }
cb323159
A
2093 case NECP_CLIENT_PARAMETER_TRANSPORT_PROTOCOL: {
2094 if (length >= sizeof(parsed_parameters->transport_protocol)) {
2095 memcpy(&parsed_parameters->transport_protocol, value, sizeof(parsed_parameters->transport_protocol));
2096 parsed_parameters->valid_fields |= NECP_PARSED_PARAMETERS_FIELD_TRANSPORT_PROTOCOL;
2097 }
2098 break;
2099 }
0a7de745
A
2100 case NECP_CLIENT_PARAMETER_PID: {
2101 if (length >= sizeof(parsed_parameters->effective_pid)) {
2102 memcpy(&parsed_parameters->effective_pid, value, sizeof(parsed_parameters->effective_pid));
2103 parsed_parameters->valid_fields |= NECP_PARSED_PARAMETERS_FIELD_EFFECTIVE_PID;
2104 }
2105 break;
2106 }
cb323159
A
2107 case NECP_CLIENT_PARAMETER_DELEGATED_UPID: {
2108 if (length >= sizeof(parsed_parameters->delegated_upid)) {
2109 memcpy(&parsed_parameters->delegated_upid, value, sizeof(parsed_parameters->delegated_upid));
2110 parsed_parameters->valid_fields |= NECP_PARSED_PARAMETERS_FIELD_DELEGATED_UPID;
2111 }
2112 break;
2113 }
2114 case NECP_CLIENT_PARAMETER_ETHERTYPE: {
2115 if (length >= sizeof(parsed_parameters->ethertype)) {
2116 memcpy(&parsed_parameters->ethertype, value, sizeof(parsed_parameters->ethertype));
2117 parsed_parameters->valid_fields |= NECP_PARSED_PARAMETERS_FIELD_ETHERTYPE;
2118 }
2119 break;
2120 }
0a7de745
A
2121 case NECP_CLIENT_PARAMETER_APPLICATION: {
2122 if (length >= sizeof(parsed_parameters->effective_uuid)) {
2123 memcpy(&parsed_parameters->effective_uuid, value, sizeof(parsed_parameters->effective_uuid));
2124 parsed_parameters->valid_fields |= NECP_PARSED_PARAMETERS_FIELD_EFFECTIVE_UUID;
2125 }
2126 break;
2127 }
2128 case NECP_CLIENT_PARAMETER_TRAFFIC_CLASS: {
2129 if (length >= sizeof(parsed_parameters->traffic_class)) {
2130 memcpy(&parsed_parameters->traffic_class, value, sizeof(parsed_parameters->traffic_class));
2131 parsed_parameters->valid_fields |= NECP_PARSED_PARAMETERS_FIELD_TRAFFIC_CLASS;
2132 }
2133 break;
2134 }
cb323159
A
2135 case NECP_CLIENT_PARAMETER_RESOLVER_TAG: {
2136 if (length > 0) {
2137 resolver_tag = (u_int8_t *)value;
2138 resolver_tag_length = length;
2139 }
2140 break;
2141 }
2142 case NECP_CLIENT_PARAMETER_DOMAIN: {
2143 if (length > 0) {
2144 client_hostname = (u_int8_t *)value;
2145 hostname_length = length;
2146 }
2147 break;
2148 }
2149 case NECP_CLIENT_PARAMETER_PARENT_ID: {
2150 if (length == sizeof(parent_id)) {
2151 uuid_copy(parent_id, value);
2152 }
2153 break;
2154 }
2155 case NECP_CLIENT_PARAMETER_LOCAL_ADDRESS_PREFERENCE: {
2156 if (length >= sizeof(parsed_parameters->local_address_preference)) {
2157 memcpy(&parsed_parameters->local_address_preference, value, sizeof(parsed_parameters->local_address_preference));
2158 parsed_parameters->valid_fields |= NECP_PARSED_PARAMETERS_FIELD_LOCAL_ADDR_PREFERENCE;
2159 }
2160 break;
2161 }
0a7de745
A
2162 default: {
2163 break;
2164 }
5ba3f43e
A
2165 }
2166 }
2167 }
2168
2169 offset += sizeof(struct necp_tlv_header) + length;
2170 }
2171
cb323159
A
2172 if (resolver_tag != NULL) {
2173 union necp_sockaddr_union remote_addr;
2174 memcpy(&remote_addr, &parsed_parameters->remote_addr, sizeof(remote_addr));
2175 remote_addr.sin.sin_port = 0;
2176 const bool validated = necp_validate_resolver_answer(parent_id,
2177 client_hostname, hostname_length,
2178 (u_int8_t *)&remote_addr, sizeof(remote_addr),
2179 resolver_tag, resolver_tag_length);
2180 if (!validated) {
2181 error = EAUTH;
2182 NECPLOG(LOG_ERR, "Failed to validate answer for hostname %s", client_hostname);
2183 }
2184 }
2185
0a7de745 2186 return error;
5ba3f43e
A
2187}
2188
2189static int
2190necp_client_parse_result(u_int8_t *result,
0a7de745
A
2191 u_int32_t result_size,
2192 union necp_sockaddr_union *local_address,
2193 union necp_sockaddr_union *remote_address,
2194 void **flow_stats)
5ba3f43e 2195{
d9a64523 2196#pragma unused(flow_stats)
5ba3f43e
A
2197 int error = 0;
2198 size_t offset = 0;
2199
2200 while ((offset + sizeof(struct necp_tlv_header)) <= result_size) {
2201 u_int8_t type = necp_buffer_get_tlv_type(result, offset);
2202 u_int32_t length = necp_buffer_get_tlv_length(result, offset);
2203
2204 if (length > 0 && (offset + sizeof(struct necp_tlv_header) + length) <= result_size) {
2205 u_int8_t *value = necp_buffer_get_tlv_value(result, offset, NULL);
2206 if (value != NULL) {
2207 switch (type) {
0a7de745
A
2208 case NECP_CLIENT_RESULT_LOCAL_ENDPOINT: {
2209 if (length >= sizeof(struct necp_client_endpoint)) {
2210 struct necp_client_endpoint *endpoint = (struct necp_client_endpoint *)(void *)value;
2211 if (local_address != NULL && necp_client_address_is_valid(&endpoint->u.sa)) {
2212 memcpy(local_address, &endpoint->u.sa, endpoint->u.sa.sa_len);
5ba3f43e 2213 }
5ba3f43e 2214 }
0a7de745
A
2215 break;
2216 }
2217 case NECP_CLIENT_RESULT_REMOTE_ENDPOINT: {
2218 if (length >= sizeof(struct necp_client_endpoint)) {
2219 struct necp_client_endpoint *endpoint = (struct necp_client_endpoint *)(void *)value;
2220 if (remote_address != NULL && necp_client_address_is_valid(&endpoint->u.sa)) {
2221 memcpy(remote_address, &endpoint->u.sa, endpoint->u.sa.sa_len);
5ba3f43e 2222 }
39037602 2223 }
0a7de745
A
2224 break;
2225 }
2226 default: {
2227 break;
2228 }
39037602
A
2229 }
2230 }
2231 }
2232
5ba3f43e 2233 offset += sizeof(struct necp_tlv_header) + length;
39037602
A
2234 }
2235
0a7de745 2236 return error;
39037602
A
2237}
2238
d9a64523
A
2239static struct necp_client_flow_registration *
2240necp_client_create_flow_registration(struct necp_fd_data *fd_data, struct necp_client *client)
2241{
2242 NECP_FD_ASSERT_LOCKED(fd_data);
2243 NECP_CLIENT_ASSERT_LOCKED(client);
2244
2245 struct necp_client_flow_registration *new_registration = mcache_alloc(necp_flow_registration_cache, MCR_SLEEP);
2246 if (new_registration == NULL) {
2247 return NULL;
2248 }
2249
2250 memset(new_registration, 0, sizeof(*new_registration));
2251
2252 new_registration->last_interface_details = combine_interface_details(IFSCOPE_NONE, NSTAT_IFNET_IS_UNKNOWN_TYPE);
2253
2254 necp_generate_client_id(new_registration->registration_id, true);
2255 LIST_INIT(&new_registration->flow_list);
2256
2257 // Add registration to client list
2258 RB_INSERT(_necp_client_flow_tree, &client->flow_registrations, new_registration);
2259
2260 // Add registration to fd list
2261 RB_INSERT(_necp_fd_flow_tree, &fd_data->flows, new_registration);
2262
2263 // Add registration to global tree for lookup
2264 NECP_FLOW_TREE_LOCK_EXCLUSIVE();
2265 RB_INSERT(_necp_client_flow_global_tree, &necp_client_flow_global_tree, new_registration);
2266 NECP_FLOW_TREE_UNLOCK();
2267
2268 new_registration->client = client;
2269
2270 // Start out assuming there is nothing to read from the flow
2271 new_registration->flow_result_read = true;
2272
2273 return new_registration;
2274}
2275
2276static void
2277necp_client_add_socket_flow(struct necp_client_flow_registration *flow_registration,
0a7de745 2278 struct inpcb *inp)
d9a64523
A
2279{
2280 struct necp_client_flow *new_flow = mcache_alloc(necp_flow_cache, MCR_SLEEP);
2281 if (new_flow == NULL) {
2282 NECPLOG0(LOG_ERR, "Failed to allocate socket flow");
2283 return;
2284 }
2285
2286 memset(new_flow, 0, sizeof(*new_flow));
2287
2288 new_flow->socket = TRUE;
2289 new_flow->u.socket_handle = inp;
2290 new_flow->u.cb = inp->necp_cb;
2291
2292 OSIncrementAtomic(&necp_socket_flow_count);
2293
2294 LIST_INSERT_HEAD(&flow_registration->flow_list, new_flow, flow_chain);
2295}
2296
cb323159
A
2297static int
2298necp_client_register_socket_inner(pid_t pid, uuid_t client_id, struct inpcb *inp, bool is_listener)
5ba3f43e
A
2299{
2300 int error = 0;
d9a64523 2301 struct necp_fd_data *client_fd = NULL;
5ba3f43e
A
2302 bool found_client = FALSE;
2303
d9a64523
A
2304 NECP_FD_LIST_LOCK_SHARED();
2305 LIST_FOREACH(client_fd, &necp_fd_list, chain) {
2306 NECP_FD_LOCK(client_fd);
2307 struct necp_client *client = necp_client_fd_find_client_and_lock(client_fd, client_id);
2308 if (client != NULL) {
2309 if (!pid || client->proc_pid == pid) {
cb323159 2310 if (is_listener) {
d9a64523 2311 found_client = TRUE;
cb323159
A
2312 } else {
2313 // Find client flow and assign from socket
2314 struct necp_client_flow_registration *flow_registration = necp_client_find_flow(client, client_id);
2315 if (flow_registration != NULL) {
2316 // Found the right client and flow registration, add a new flow
d9a64523
A
2317 found_client = TRUE;
2318 necp_client_add_socket_flow(flow_registration, inp);
cb323159
A
2319 } else if (RB_EMPTY(&client->flow_registrations) && !necp_client_id_is_flow(client_id)) {
2320 // No flows yet on this client, add a new registration
2321 flow_registration = necp_client_create_flow_registration(client_fd, client);
2322 if (flow_registration == NULL) {
2323 error = ENOMEM;
2324 } else {
2325 // Add a new flow
2326 found_client = TRUE;
2327 necp_client_add_socket_flow(flow_registration, inp);
2328 }
d9a64523
A
2329 }
2330 }
2331 }
5ba3f43e 2332
d9a64523 2333 NECP_CLIENT_UNLOCK(client);
5ba3f43e 2334 }
d9a64523 2335 NECP_FD_UNLOCK(client_fd);
5ba3f43e 2336
d9a64523
A
2337 if (found_client) {
2338 break;
2339 }
5ba3f43e 2340 }
d9a64523 2341 NECP_FD_LIST_UNLOCK();
5ba3f43e
A
2342
2343 if (!found_client) {
2344 error = ENOENT;
2345 } else {
d9a64523 2346 // Count the sockets that have the NECP client UUID set
5ba3f43e
A
2347 struct socket *so = inp->inp_socket;
2348 if (!(so->so_flags1 & SOF1_HAS_NECP_CLIENT_UUID)) {
2349 so->so_flags1 |= SOF1_HAS_NECP_CLIENT_UUID;
2350 INC_ATOMIC_INT64_LIM(net_api_stats.nas_socket_necp_clientuuid_total);
2351 }
2352 }
2353
0a7de745 2354 return error;
5ba3f43e
A
2355}
2356
cb323159
A
2357int
2358necp_client_register_socket_flow(pid_t pid, uuid_t client_id, struct inpcb *inp)
2359{
2360 return necp_client_register_socket_inner(pid, client_id, inp, false);
2361}
2362
2363int
2364necp_client_register_socket_listener(pid_t pid, uuid_t client_id, struct inpcb *inp)
2365{
2366 return necp_client_register_socket_inner(pid, client_id, inp, true);
2367}
2368
2369
5ba3f43e 2370static void
d9a64523 2371necp_client_add_multipath_interface_flows(struct necp_client_flow_registration *flow_registration,
0a7de745
A
2372 struct necp_client *client,
2373 struct mppcb *mpp)
5ba3f43e 2374{
d9a64523
A
2375 flow_registration->interface_handle = mpp;
2376 flow_registration->interface_cb = mpp->necp_cb;
5ba3f43e 2377
d9a64523
A
2378 proc_t proc = proc_find(client->proc_pid);
2379 if (proc == PROC_NULL) {
2380 return;
2381 }
5ba3f43e 2382
d9a64523
A
2383 // Traverse all interfaces and add a tracking flow if needed
2384 necp_flow_add_interface_flows(proc, client, flow_registration, true);
2385
2386 proc_rele(proc);
2387 proc = PROC_NULL;
2388}
2389
2390int
2391necp_client_register_multipath_cb(pid_t pid, uuid_t client_id, struct mppcb *mpp)
2392{
2393 int error = 0;
2394 struct necp_fd_data *client_fd = NULL;
2395 bool found_client = FALSE;
2396
2397 NECP_FD_LIST_LOCK_SHARED();
2398 LIST_FOREACH(client_fd, &necp_fd_list, chain) {
2399 NECP_FD_LOCK(client_fd);
2400 struct necp_client *client = necp_client_fd_find_client_and_lock(client_fd, client_id);
2401 if (client != NULL) {
2402 if (!pid || client->proc_pid == pid) {
2403 struct necp_client_flow_registration *flow_registration = necp_client_find_flow(client, client_id);
2404 if (flow_registration != NULL) {
2405 // Found the right client and flow registration, add a new flow
2406 found_client = TRUE;
2407 necp_client_add_multipath_interface_flows(flow_registration, client, mpp);
2408 } else if (RB_EMPTY(&client->flow_registrations) && !necp_client_id_is_flow(client_id)) {
2409 // No flows yet on this client, add a new registration
2410 flow_registration = necp_client_create_flow_registration(client_fd, client);
2411 if (flow_registration == NULL) {
2412 error = ENOMEM;
2413 } else {
2414 // Add a new flow
2415 found_client = TRUE;
2416 necp_client_add_multipath_interface_flows(flow_registration, client, mpp);
2417 }
2418 }
2419 }
2420
2421 NECP_CLIENT_UNLOCK(client);
2422 }
2423 NECP_FD_UNLOCK(client_fd);
2424
2425 if (found_client) {
2426 break;
2427 }
2428 }
2429 NECP_FD_LIST_UNLOCK();
2430
2431 if (!found_client && error == 0) {
2432 error = ENOENT;
2433 }
2434
0a7de745 2435 return error;
d9a64523
A
2436}
2437
0a7de745
A
2438#define NETAGENT_DOMAIN_RADIO_MANAGER "WirelessRadioManager"
2439#define NETAGENT_TYPE_RADIO_MANAGER "WirelessRadioManager:BB Manager"
d9a64523
A
2440
2441static int
2442necp_client_lookup_bb_radio_manager(struct necp_client *client,
0a7de745 2443 uuid_t netagent_uuid)
d9a64523
A
2444{
2445 char netagent_domain[NETAGENT_DOMAINSIZE];
2446 char netagent_type[NETAGENT_TYPESIZE];
2447 struct necp_aggregate_result result;
2448 proc_t proc;
2449 int error;
2450
2451 proc = proc_find(client->proc_pid);
2452 if (proc == PROC_NULL) {
2453 return ESRCH;
2454 }
2455
2456 error = necp_application_find_policy_match_internal(proc, client->parameters, (u_int32_t)client->parameters_length,
ea3f0419 2457 &result, NULL, NULL, 0, NULL, NULL, NULL, NULL, NULL, true, true, NULL);
d9a64523
A
2458
2459 proc_rele(proc);
2460 proc = PROC_NULL;
2461
2462 if (error) {
2463 return error;
2464 }
2465
2466 for (int i = 0; i < NECP_MAX_NETAGENTS; i++) {
2467 if (uuid_is_null(result.netagents[i])) {
2468 // Passed end of valid agents
2469 break;
2470 }
2471
2472 memset(&netagent_domain, 0, NETAGENT_DOMAINSIZE);
2473 memset(&netagent_type, 0, NETAGENT_TYPESIZE);
2474 if (netagent_get_agent_domain_and_type(result.netagents[i], netagent_domain, netagent_type) == FALSE) {
2475 continue;
2476 }
2477
2478 if (strncmp(netagent_domain, NETAGENT_DOMAIN_RADIO_MANAGER, NETAGENT_DOMAINSIZE) != 0) {
5ba3f43e
A
2479 continue;
2480 }
2481
d9a64523
A
2482 if (strncmp(netagent_type, NETAGENT_TYPE_RADIO_MANAGER, NETAGENT_TYPESIZE) != 0) {
2483 continue;
2484 }
2485
2486 uuid_copy(netagent_uuid, result.netagents[i]);
5ba3f43e 2487
d9a64523
A
2488 break;
2489 }
2490
2491 return 0;
2492}
2493
2494static int
2495necp_client_assert_bb_radio_manager_common(struct necp_client *client, bool assert)
2496{
2497 uuid_t netagent_uuid;
2498 uint8_t assert_type;
2499 int error;
2500
2501 error = necp_client_lookup_bb_radio_manager(client, netagent_uuid);
2502 if (error) {
2503 NECPLOG0(LOG_ERR, "BB radio manager agent not found");
2504 return error;
2505 }
2506
2507 // Before unasserting, verify that the assertion was already taken
2508 if (assert == FALSE) {
2509 assert_type = NETAGENT_MESSAGE_TYPE_CLIENT_UNASSERT;
2510
2511 if (!necp_client_remove_assertion(client, netagent_uuid)) {
2512 return EINVAL;
5ba3f43e 2513 }
d9a64523
A
2514 } else {
2515 assert_type = NETAGENT_MESSAGE_TYPE_CLIENT_ASSERT;
2516 }
2517
2518 error = netagent_client_message(netagent_uuid, client->client_id, client->proc_pid, client->agent_handle, assert_type);
2519 if (error) {
2520 NECPLOG0(LOG_ERR, "netagent_client_message failed");
2521 return error;
5ba3f43e 2522 }
d9a64523
A
2523
2524 // Only save the assertion if the action succeeded
2525 if (assert == TRUE) {
2526 necp_client_add_assertion(client, netagent_uuid);
2527 }
2528
2529 return 0;
5ba3f43e
A
2530}
2531
2532int
d9a64523 2533necp_client_assert_bb_radio_manager(uuid_t client_id, bool assert)
5ba3f43e 2534{
d9a64523 2535 struct necp_client *client;
5ba3f43e 2536 int error = 0;
5ba3f43e
A
2537
2538 NECP_CLIENT_TREE_LOCK_SHARED();
2539
d9a64523 2540 client = necp_find_client_and_lock(client_id);
5ba3f43e 2541
d9a64523
A
2542 if (client) {
2543 // Found the right client!
2544 error = necp_client_assert_bb_radio_manager_common(client, assert);
5ba3f43e
A
2545
2546 NECP_CLIENT_UNLOCK(client);
d9a64523
A
2547 } else {
2548 NECPLOG0(LOG_ERR, "Couldn't find client");
2549 error = ENOENT;
5ba3f43e
A
2550 }
2551
2552 NECP_CLIENT_TREE_UNLOCK();
2553
0a7de745 2554 return error;
5ba3f43e
A
2555}
2556
5ba3f43e
A
2557static int
2558necp_client_unregister_socket_flow(uuid_t client_id, void *handle)
39037602
A
2559{
2560 int error = 0;
2561 struct necp_fd_data *client_fd = NULL;
2562 bool found_client = FALSE;
2563 bool client_updated = FALSE;
2564
5ba3f43e
A
2565 NECP_FD_LIST_LOCK_SHARED();
2566 LIST_FOREACH(client_fd, &necp_fd_list, chain) {
2567 NECP_FD_LOCK(client_fd);
2568
2569 struct necp_client *client = necp_client_fd_find_client_and_lock(client_fd, client_id);
2570 if (client != NULL) {
d9a64523
A
2571 struct necp_client_flow_registration *flow_registration = necp_client_find_flow(client, client_id);
2572 if (flow_registration != NULL) {
2573 // Found the right client and flow!
2574 found_client = TRUE;
5ba3f43e 2575
d9a64523
A
2576 // Remove flow assignment
2577 struct necp_client_flow *search_flow = NULL;
2578 struct necp_client_flow *temp_flow = NULL;
2579 LIST_FOREACH_SAFE(search_flow, &flow_registration->flow_list, flow_chain, temp_flow) {
2580 if (search_flow->socket && search_flow->u.socket_handle == handle) {
2581 if (search_flow->assigned_results != NULL) {
2582 FREE(search_flow->assigned_results, M_NETAGENT);
2583 search_flow->assigned_results = NULL;
2584 }
2585 client_updated = TRUE;
2586 flow_registration->flow_result_read = FALSE;
2587 LIST_REMOVE(search_flow, flow_chain);
2588 OSDecrementAtomic(&necp_socket_flow_count);
2589 mcache_free(necp_flow_cache, search_flow);
5ba3f43e 2590 }
5ba3f43e
A
2591 }
2592 }
2593
2594 NECP_CLIENT_UNLOCK(client);
2595 }
2596
2597 if (client_updated) {
5ba3f43e
A
2598 necp_fd_notify(client_fd, true);
2599 }
2600 NECP_FD_UNLOCK(client_fd);
2601
2602 if (found_client) {
2603 break;
2604 }
2605 }
2606 NECP_FD_LIST_UNLOCK();
2607
2608 if (!found_client) {
2609 error = ENOENT;
2610 }
2611
0a7de745 2612 return error;
5ba3f43e
A
2613}
2614
2615static int
2616necp_client_unregister_multipath_cb(uuid_t client_id, void *handle)
2617{
2618 int error = 0;
2619 bool found_client = FALSE;
2620
2621 NECP_CLIENT_TREE_LOCK_SHARED();
2622
d9a64523 2623 struct necp_client *client = necp_find_client_and_lock(client_id);
5ba3f43e 2624 if (client != NULL) {
d9a64523
A
2625 struct necp_client_flow_registration *flow_registration = necp_client_find_flow(client, client_id);
2626 if (flow_registration != NULL) {
2627 // Found the right client and flow!
2628 found_client = TRUE;
5ba3f43e 2629
d9a64523
A
2630 // Remove flow assignment
2631 struct necp_client_flow *search_flow = NULL;
2632 struct necp_client_flow *temp_flow = NULL;
2633 LIST_FOREACH_SAFE(search_flow, &flow_registration->flow_list, flow_chain, temp_flow) {
2634 if (!search_flow->socket && !search_flow->nexus &&
0a7de745 2635 search_flow->u.socket_handle == handle) {
d9a64523
A
2636 search_flow->u.socket_handle = NULL;
2637 search_flow->u.cb = NULL;
2638 }
5ba3f43e 2639 }
39037602 2640
d9a64523
A
2641 flow_registration->interface_handle = NULL;
2642 flow_registration->interface_cb = NULL;
2643 }
5ba3f43e
A
2644
2645 NECP_CLIENT_UNLOCK(client);
2646 }
2647
2648 NECP_CLIENT_TREE_UNLOCK();
2649
2650 if (!found_client) {
2651 error = ENOENT;
2652 }
2653
0a7de745 2654 return error;
5ba3f43e
A
2655}
2656
2657int
2658necp_client_assign_from_socket(pid_t pid, uuid_t client_id, struct inpcb *inp)
2659{
2660 int error = 0;
2661 struct necp_fd_data *client_fd = NULL;
2662 bool found_client = FALSE;
2663 bool client_updated = FALSE;
2664
2665 NECP_FD_LIST_LOCK_SHARED();
39037602 2666 LIST_FOREACH(client_fd, &necp_fd_list, chain) {
5ba3f43e
A
2667 if (pid && client_fd->proc_pid != pid) {
2668 continue;
2669 }
39037602 2670
5ba3f43e
A
2671 proc_t proc = proc_find(client_fd->proc_pid);
2672 if (proc == PROC_NULL) {
2673 continue;
2674 }
2675
2676 NECP_FD_LOCK(client_fd);
2677
2678 struct necp_client *client = necp_client_fd_find_client_and_lock(client_fd, client_id);
2679 if (client != NULL) {
d9a64523
A
2680 struct necp_client_flow_registration *flow_registration = necp_client_find_flow(client, client_id);
2681 if (flow_registration == NULL && RB_EMPTY(&client->flow_registrations) && !necp_client_id_is_flow(client_id)) {
2682 // No flows yet on this client, add a new registration
2683 flow_registration = necp_client_create_flow_registration(client_fd, client);
2684 if (flow_registration == NULL) {
2685 error = ENOMEM;
2686 }
2687 }
2688 if (flow_registration != NULL) {
2689 // Found the right client and flow!
2690 found_client = TRUE;
5ba3f43e 2691
d9a64523
A
2692 struct necp_client_flow *flow = NULL;
2693 LIST_FOREACH(flow, &flow_registration->flow_list, flow_chain) {
2694 if (flow->socket && flow->u.socket_handle == inp) {
2695 // Release prior results and route
2696 if (flow->assigned_results != NULL) {
2697 FREE(flow->assigned_results, M_NETAGENT);
2698 flow->assigned_results = NULL;
2699 }
5ba3f43e 2700
d9a64523
A
2701 ifnet_t ifp = NULL;
2702 if ((inp->inp_flags & INP_BOUND_IF) && inp->inp_boundifp) {
2703 ifp = inp->inp_boundifp;
2704 } else {
2705 ifp = inp->inp_last_outifp;
2706 }
5ba3f43e 2707
d9a64523
A
2708 if (ifp != NULL) {
2709 flow->interface_index = ifp->if_index;
2710 } else {
2711 flow->interface_index = IFSCOPE_NONE;
2712 }
5ba3f43e 2713
d9a64523
A
2714 if (inp->inp_vflag & INP_IPV4) {
2715 flow->local_addr.sin.sin_family = AF_INET;
2716 flow->local_addr.sin.sin_len = sizeof(struct sockaddr_in);
2717 flow->local_addr.sin.sin_port = inp->inp_lport;
2718 memcpy(&flow->local_addr.sin.sin_addr, &inp->inp_laddr, sizeof(struct in_addr));
2719
2720 flow->remote_addr.sin.sin_family = AF_INET;
2721 flow->remote_addr.sin.sin_len = sizeof(struct sockaddr_in);
2722 flow->remote_addr.sin.sin_port = inp->inp_fport;
2723 memcpy(&flow->remote_addr.sin.sin_addr, &inp->inp_faddr, sizeof(struct in_addr));
2724 } else if (inp->inp_vflag & INP_IPV6) {
2725 in6_ip6_to_sockaddr(&inp->in6p_laddr, inp->inp_lport, &flow->local_addr.sin6, sizeof(flow->local_addr));
2726 in6_ip6_to_sockaddr(&inp->in6p_faddr, inp->inp_fport, &flow->remote_addr.sin6, sizeof(flow->remote_addr));
2727 }
5ba3f43e 2728
d9a64523
A
2729 flow->viable = necp_client_flow_is_viable(proc, client, flow);
2730
2731 uuid_t empty_uuid;
2732 uuid_clear(empty_uuid);
2733 flow->assigned = TRUE;
2734 flow->assigned_results = necp_create_nexus_assign_message(empty_uuid, 0, NULL, 0,
0a7de745
A
2735 (struct necp_client_endpoint *)&flow->local_addr,
2736 (struct necp_client_endpoint *)&flow->remote_addr,
cb323159 2737 NULL, 0, NULL, &flow->assigned_results_length);
d9a64523
A
2738 flow_registration->flow_result_read = FALSE;
2739 client_updated = TRUE;
2740 break;
2741 }
39037602
A
2742 }
2743 }
5ba3f43e
A
2744
2745 NECP_CLIENT_UNLOCK(client);
39037602
A
2746 }
2747 if (client_updated) {
2748 necp_fd_notify(client_fd, true);
2749 }
5ba3f43e
A
2750 NECP_FD_UNLOCK(client_fd);
2751
2752 proc_rele(proc);
2753 proc = PROC_NULL;
39037602
A
2754
2755 if (found_client) {
2756 break;
2757 }
2758 }
5ba3f43e 2759 NECP_FD_LIST_UNLOCK();
39037602 2760
d9a64523
A
2761 if (error == 0) {
2762 if (!found_client) {
2763 error = ENOENT;
2764 } else if (!client_updated) {
2765 error = EINVAL;
2766 }
5ba3f43e
A
2767 }
2768
0a7de745 2769 return error;
5ba3f43e
A
2770}
2771
cb323159
A
2772bool
2773necp_socket_is_allowed_to_recv_on_interface(struct inpcb *inp, ifnet_t interface)
2774{
2775 if (interface == NULL ||
2776 inp == NULL ||
2777 !(inp->inp_flags2 & INP2_EXTERNAL_PORT) ||
2778 uuid_is_null(inp->necp_client_uuid)) {
2779 // If there's no interface or client ID to check,
2780 // or if this is not a listener, pass.
2781 // Outbound connections will have already been
2782 // validated for policy.
2783 return TRUE;
2784 }
2785
2786 // Only filter out listener sockets (no remote address specified)
2787 if ((inp->inp_vflag & INP_IPV4) &&
2788 inp->inp_faddr.s_addr != INADDR_ANY) {
2789 return TRUE;
2790 }
2791 if ((inp->inp_vflag & INP_IPV6) &&
2792 !IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr)) {
2793 return TRUE;
2794 }
2795
2796 bool allowed = TRUE;
2797
2798 NECP_CLIENT_TREE_LOCK_SHARED();
2799
2800 struct necp_client *client = necp_find_client_and_lock(inp->necp_client_uuid);
2801 if (client != NULL) {
2802 struct necp_client_parsed_parameters *parsed_parameters = NULL;
2803
2804 MALLOC(parsed_parameters, struct necp_client_parsed_parameters *, sizeof(*parsed_parameters), M_NECP, (M_WAITOK | M_ZERO));
2805 if (parsed_parameters != NULL) {
2806 int error = necp_client_parse_parameters(client->parameters, (u_int32_t)client->parameters_length, parsed_parameters);
2807 if (error == 0) {
2808 if (!necp_ifnet_matches_parameters(interface, parsed_parameters, 0, NULL, true, false)) {
2809 allowed = FALSE;
2810 }
2811 }
2812 FREE(parsed_parameters, M_NECP);
2813 }
2814
2815 NECP_CLIENT_UNLOCK(client);
2816 }
2817
2818 NECP_CLIENT_TREE_UNLOCK();
2819
2820 return allowed;
2821}
2822
5ba3f43e
A
2823int
2824necp_update_flow_protoctl_event(uuid_t netagent_uuid, uuid_t client_id,
2825 uint32_t protoctl_event_code, uint32_t protoctl_event_val,
2826 uint32_t protoctl_event_tcp_seq_number)
2827{
2828 int error = 0;
2829 struct necp_fd_data *client_fd = NULL;
2830 bool found_client = FALSE;
2831 bool client_updated = FALSE;
2832
2833 NECP_FD_LIST_LOCK_SHARED();
2834 LIST_FOREACH(client_fd, &necp_fd_list, chain) {
2835 proc_t proc = proc_find(client_fd->proc_pid);
2836 if (proc == PROC_NULL) {
2837 continue;
2838 }
2839
2840 NECP_FD_LOCK(client_fd);
2841
2842 struct necp_client *client = necp_client_fd_find_client_and_lock(client_fd, client_id);
2843 if (client != NULL) {
d9a64523
A
2844 struct necp_client_flow_registration *flow_registration = necp_client_find_flow(client, client_id);
2845 if (flow_registration != NULL) {
2846 // Found the right client and flow!
2847 found_client = TRUE;
5ba3f43e 2848
d9a64523
A
2849 struct necp_client_flow *flow = NULL;
2850 LIST_FOREACH(flow, &flow_registration->flow_list, flow_chain) {
2851 // Verify that the client nexus agent matches
2852 if (flow->nexus &&
0a7de745
A
2853 uuid_compare(flow->u.nexus_agent,
2854 netagent_uuid) == 0) {
d9a64523
A
2855 flow->has_protoctl_event = TRUE;
2856 flow->protoctl_event.protoctl_event_code = protoctl_event_code;
2857 flow->protoctl_event.protoctl_event_val = protoctl_event_val;
2858 flow->protoctl_event.protoctl_event_tcp_seq_num = protoctl_event_tcp_seq_number;
2859 flow_registration->flow_result_read = FALSE;
2860 client_updated = TRUE;
2861 break;
2862 }
5ba3f43e
A
2863 }
2864 }
2865
2866 NECP_CLIENT_UNLOCK(client);
2867 }
2868
2869 if (client_updated) {
2870 necp_fd_notify(client_fd, true);
2871 }
2872
2873 NECP_FD_UNLOCK(client_fd);
2874 proc_rele(proc);
2875 proc = PROC_NULL;
2876
2877 if (found_client) {
2878 break;
2879 }
2880 }
2881 NECP_FD_LIST_UNLOCK();
39037602 2882
5ba3f43e
A
2883 if (!found_client) {
2884 error = ENOENT;
2885 } else if (!client_updated) {
2886 error = EINVAL;
2887 }
0a7de745 2888 return error;
5ba3f43e
A
2889}
2890
2891static bool
a39ff7e2 2892necp_assign_client_result_locked(struct proc *proc,
0a7de745
A
2893 struct necp_fd_data *client_fd,
2894 struct necp_client *client,
2895 struct necp_client_flow_registration *flow_registration,
2896 uuid_t netagent_uuid,
2897 u_int8_t *assigned_results,
2898 size_t assigned_results_length,
2899 bool notify_fd)
5ba3f43e
A
2900{
2901 bool client_updated = FALSE;
2902
2903 NECP_FD_ASSERT_LOCKED(client_fd);
2904 NECP_CLIENT_ASSERT_LOCKED(client);
2905
2906 struct necp_client_flow *flow = NULL;
d9a64523 2907 LIST_FOREACH(flow, &flow_registration->flow_list, flow_chain) {
5ba3f43e
A
2908 // Verify that the client nexus agent matches
2909 if (flow->nexus &&
0a7de745 2910 uuid_compare(flow->u.nexus_agent, netagent_uuid) == 0) {
5ba3f43e
A
2911 // Release prior results and route
2912 if (flow->assigned_results != NULL) {
2913 FREE(flow->assigned_results, M_NETAGENT);
2914 flow->assigned_results = NULL;
2915 }
2916
d9a64523 2917 void *nexus_stats = NULL;
5ba3f43e
A
2918 if (assigned_results != NULL && assigned_results_length > 0) {
2919 int error = necp_client_parse_result(assigned_results, (u_int32_t)assigned_results_length,
0a7de745 2920 &flow->local_addr, &flow->remote_addr, &nexus_stats);
5ba3f43e
A
2921 VERIFY(error == 0);
2922 }
2923
2924 flow->viable = necp_client_flow_is_viable(proc, client, flow);
2925
2926 flow->assigned = TRUE;
2927 flow->assigned_results = assigned_results;
2928 flow->assigned_results_length = assigned_results_length;
d9a64523 2929 flow_registration->flow_result_read = FALSE;
5ba3f43e
A
2930 client_updated = TRUE;
2931 break;
2932 }
2933 }
2934
a39ff7e2 2935 if (client_updated && notify_fd) {
5ba3f43e
A
2936 necp_fd_notify(client_fd, true);
2937 }
2938
2939 // if not updated, client must free assigned_results
0a7de745 2940 return client_updated;
5ba3f43e
A
2941}
2942
2943int
2944necp_assign_client_result(uuid_t netagent_uuid, uuid_t client_id,
0a7de745 2945 u_int8_t *assigned_results, size_t assigned_results_length)
5ba3f43e
A
2946{
2947 int error = 0;
2948 struct necp_fd_data *client_fd = NULL;
2949 bool found_client = FALSE;
2950 bool client_updated = FALSE;
2951
2952 NECP_FD_LIST_LOCK_SHARED();
2953
2954 LIST_FOREACH(client_fd, &necp_fd_list, chain) {
2955 proc_t proc = proc_find(client_fd->proc_pid);
2956 if (proc == PROC_NULL) {
2957 continue;
2958 }
2959
2960 NECP_FD_LOCK(client_fd);
2961 struct necp_client *client = necp_client_fd_find_client_and_lock(client_fd, client_id);
2962 if (client != NULL) {
d9a64523
A
2963 struct necp_client_flow_registration *flow_registration = necp_client_find_flow(client, client_id);
2964 if (flow_registration != NULL) {
2965 // Found the right client and flow!
2966 found_client = TRUE;
2967 if (necp_assign_client_result_locked(proc, client_fd, client, flow_registration, netagent_uuid,
0a7de745 2968 assigned_results, assigned_results_length, true)) {
d9a64523
A
2969 client_updated = TRUE;
2970 }
5ba3f43e
A
2971 }
2972
2973 NECP_CLIENT_UNLOCK(client);
2974 }
2975 NECP_FD_UNLOCK(client_fd);
2976
2977 proc_rele(proc);
2978 proc = PROC_NULL;
2979
d9a64523
A
2980 if (found_client) {
2981 break;
2982 }
2983 }
2984
2985 NECP_FD_LIST_UNLOCK();
2986
2987 // upon error, client must free assigned_results
2988 if (!found_client) {
2989 error = ENOENT;
2990 } else if (!client_updated) {
2991 error = EINVAL;
2992 }
2993
0a7de745 2994 return error;
d9a64523
A
2995}
2996
2997/// Client updating
2998
2999static bool
3000necp_update_parsed_parameters(struct necp_client_parsed_parameters *parsed_parameters,
0a7de745 3001 struct necp_aggregate_result *result)
d9a64523
A
3002{
3003 if (parsed_parameters == NULL ||
0a7de745
A
3004 result == NULL) {
3005 return false;
d9a64523
A
3006 }
3007
3008 bool updated = false;
3009 for (int i = 0; i < NECP_MAX_NETAGENTS; i++) {
3010 if (uuid_is_null(result->netagents[i])) {
3011 // Passed end of valid agents
3012 break;
3013 }
3014
3015 if (!(result->netagent_use_flags[i] & NECP_AGENT_USE_FLAG_SCOPE)) {
3016 // Not a scoped agent, ignore
3017 continue;
3018 }
3019
3020 // This is a scoped agent. Add it to the required agents.
3021 if (parsed_parameters->valid_fields & NECP_PARSED_PARAMETERS_FIELD_REQUIRED_AGENT) {
3022 // Already some required agents, add this at the end
cb323159 3023 for (int j = 0; j < NECP_MAX_AGENT_PARAMETERS; j++) {
d9a64523
A
3024 if (uuid_compare(parsed_parameters->required_netagents[j], result->netagents[i]) == 0) {
3025 // Already required, break
3026 break;
3027 }
3028 if (uuid_is_null(parsed_parameters->required_netagents[j])) {
3029 // Add here
3030 memcpy(&parsed_parameters->required_netagents[j], result->netagents[i], sizeof(uuid_t));
3031 updated = true;
3032 break;
3033 }
3034 }
3035 } else {
3036 // No required agents yet, add this one
3037 parsed_parameters->valid_fields |= NECP_PARSED_PARAMETERS_FIELD_REQUIRED_AGENT;
3038 memcpy(&parsed_parameters->required_netagents[0], result->netagents[i], sizeof(uuid_t));
3039 updated = true;
3040 }
3041
3042 // Remove requirements for agents of the same type
3043 if (parsed_parameters->valid_fields & NECP_PARSED_PARAMETERS_FIELD_REQUIRED_AGENT_TYPE) {
3044 char remove_agent_domain[NETAGENT_DOMAINSIZE] = { 0 };
3045 char remove_agent_type[NETAGENT_TYPESIZE] = { 0 };
3046 if (netagent_get_agent_domain_and_type(result->netagents[i], remove_agent_domain, remove_agent_type)) {
cb323159 3047 for (int j = 0; j < NECP_MAX_AGENT_PARAMETERS; j++) {
d9a64523 3048 if (strlen(parsed_parameters->required_netagent_types[j].netagent_domain) == 0 &&
0a7de745 3049 strlen(parsed_parameters->required_netagent_types[j].netagent_type) == 0) {
d9a64523
A
3050 break;
3051 }
3052
3053 if (strncmp(parsed_parameters->required_netagent_types[j].netagent_domain, remove_agent_domain, NETAGENT_DOMAINSIZE) == 0 &&
0a7de745 3054 strncmp(parsed_parameters->required_netagent_types[j].netagent_type, remove_agent_type, NETAGENT_TYPESIZE) == 0) {
d9a64523
A
3055 updated = true;
3056
cb323159 3057 if (j == NECP_MAX_AGENT_PARAMETERS - 1) {
d9a64523 3058 // Last field, just clear and break
cb323159 3059 memset(&parsed_parameters->required_netagent_types[NECP_MAX_AGENT_PARAMETERS - 1], 0, sizeof(struct necp_client_parameter_netagent_type));
d9a64523
A
3060 break;
3061 } else {
3062 // Move the parameters down, clear the last entry
3063 memmove(&parsed_parameters->required_netagent_types[j],
0a7de745 3064 &parsed_parameters->required_netagent_types[j + 1],
cb323159
A
3065 sizeof(struct necp_client_parameter_netagent_type) * (NECP_MAX_AGENT_PARAMETERS - (j + 1)));
3066 memset(&parsed_parameters->required_netagent_types[NECP_MAX_AGENT_PARAMETERS - 1], 0, sizeof(struct necp_client_parameter_netagent_type));
d9a64523
A
3067 // Continue, don't increment but look at the new shifted item instead
3068 continue;
3069 }
3070 }
3071
3072 // Increment j to look at the next agent type parameter
3073 j++;
3074 }
3075 }
3076 }
3077 }
3078
3079 if (updated &&
0a7de745
A
3080 parsed_parameters->required_interface_index != IFSCOPE_NONE &&
3081 (parsed_parameters->valid_fields & NECP_PARSED_PARAMETERS_FIELD_REQUIRED_IF) == 0) {
d9a64523
A
3082 // A required interface index was added after the fact. Clear it.
3083 parsed_parameters->required_interface_index = IFSCOPE_NONE;
3084 }
3085
3086
0a7de745 3087 return updated;
d9a64523
A
3088}
3089
3090static inline bool
3091necp_agent_types_match(const char *agent_domain1, const char *agent_type1,
0a7de745 3092 const char *agent_domain2, const char *agent_type2)
d9a64523 3093{
0a7de745
A
3094 return (strlen(agent_domain1) == 0 ||
3095 strncmp(agent_domain2, agent_domain1, NETAGENT_DOMAINSIZE) == 0) &&
3096 (strlen(agent_type1) == 0 ||
3097 strncmp(agent_type2, agent_type1, NETAGENT_TYPESIZE) == 0);
d9a64523
A
3098}
3099
3100static inline bool
3101necp_calculate_client_result(proc_t proc,
0a7de745
A
3102 struct necp_client *client,
3103 struct necp_client_parsed_parameters *parsed_parameters,
3104 struct necp_aggregate_result *result,
cb323159
A
3105 u_int32_t *flags,
3106 u_int32_t *reason,
3107 struct necp_client_endpoint *v4_gateway,
ea3f0419
A
3108 struct necp_client_endpoint *v6_gateway,
3109 uuid_t *override_euuid)
d9a64523
A
3110{
3111 struct rtentry *route = NULL;
3112
3113 // Check parameters to find best interface
3114 bool validate_agents = false;
3115 u_int matching_if_index = 0;
3116 if (necp_find_matching_interface_index(parsed_parameters, &matching_if_index, &validate_agents)) {
3117 if (matching_if_index != 0) {
3118 parsed_parameters->required_interface_index = matching_if_index;
3119 }
3120 // Interface found or not needed, match policy.
3121 memset(result, 0, sizeof(*result));
3122 int error = necp_application_find_policy_match_internal(proc, client->parameters,
0a7de745 3123 (u_int32_t)client->parameters_length,
cb323159
A
3124 result, flags, reason, matching_if_index,
3125 NULL, NULL,
3126 v4_gateway, v6_gateway,
ea3f0419
A
3127 &route, false, true,
3128 override_euuid);
d9a64523
A
3129 if (error != 0) {
3130 if (route != NULL) {
3131 rtfree(route);
3132 }
0a7de745 3133 return FALSE;
d9a64523
A
3134 }
3135
3136 if (validate_agents) {
3137 bool requirement_failed = FALSE;
3138 if (parsed_parameters->valid_fields & NECP_PARSED_PARAMETERS_FIELD_REQUIRED_AGENT) {
cb323159 3139 for (int i = 0; i < NECP_MAX_AGENT_PARAMETERS; i++) {
d9a64523
A
3140 if (uuid_is_null(parsed_parameters->required_netagents[i])) {
3141 break;
3142 }
3143
3144 bool requirement_found = FALSE;
3145 for (int j = 0; j < NECP_MAX_NETAGENTS; j++) {
3146 if (uuid_is_null(result->netagents[j])) {
3147 break;
3148 }
3149
3150 if (uuid_compare(parsed_parameters->required_netagents[i], result->netagents[j]) == 0) {
3151 requirement_found = TRUE;
3152 break;
3153 }
3154 }
3155
3156 if (!requirement_found) {
3157 requirement_failed = TRUE;
3158 break;
3159 }
3160 }
3161 }
3162
3163 if (!requirement_failed && parsed_parameters->valid_fields & NECP_PARSED_PARAMETERS_FIELD_REQUIRED_AGENT_TYPE) {
cb323159 3164 for (int i = 0; i < NECP_MAX_AGENT_PARAMETERS; i++) {
d9a64523 3165 if (strlen(parsed_parameters->required_netagent_types[i].netagent_domain) == 0 &&
0a7de745 3166 strlen(parsed_parameters->required_netagent_types[i].netagent_type) == 0) {
d9a64523
A
3167 break;
3168 }
3169
3170 bool requirement_found = FALSE;
3171 for (int j = 0; j < NECP_MAX_NETAGENTS; j++) {
3172 if (uuid_is_null(result->netagents[j])) {
3173 break;
3174 }
3175
3176 char policy_agent_domain[NETAGENT_DOMAINSIZE] = { 0 };
3177 char policy_agent_type[NETAGENT_TYPESIZE] = { 0 };
3178
3179 if (netagent_get_agent_domain_and_type(result->netagents[j], policy_agent_domain, policy_agent_type)) {
3180 if (necp_agent_types_match(parsed_parameters->required_netagent_types[i].netagent_domain,
0a7de745
A
3181 parsed_parameters->required_netagent_types[i].netagent_type,
3182 policy_agent_domain, policy_agent_type)) {
d9a64523
A
3183 requirement_found = TRUE;
3184 break;
3185 }
3186 }
3187 }
3188
3189 if (!requirement_found) {
3190 requirement_failed = TRUE;
3191 break;
3192 }
3193 }
3194 }
3195
3196 if (requirement_failed) {
3197 // Agent requirement failed. Clear out the whole result, make everything fail.
3198 memset(result, 0, sizeof(*result));
3199 if (route != NULL) {
3200 rtfree(route);
3201 }
0a7de745 3202 return TRUE;
d9a64523 3203 }
5ba3f43e 3204 }
5ba3f43e 3205
d9a64523
A
3206 // Reset current route
3207 NECP_CLIENT_ROUTE_LOCK(client);
3208 if (client->current_route != NULL) {
3209 rtfree(client->current_route);
3210 }
3211 client->current_route = route;
3212 NECP_CLIENT_ROUTE_UNLOCK(client);
3213 } else {
3214 // Interface not found. Clear out the whole result, make everything fail.
3215 memset(result, 0, sizeof(*result));
39037602
A
3216 }
3217
0a7de745 3218 return TRUE;
39037602
A
3219}
3220
cb323159
A
3221#define NECP_PARSED_PARAMETERS_REQUIRED_FIELDS (NECP_PARSED_PARAMETERS_FIELD_REQUIRED_IF | \
3222 NECP_PARSED_PARAMETERS_FIELD_REQUIRED_IFTYPE | \
3223 NECP_PARSED_PARAMETERS_FIELD_REQUIRED_AGENT | \
3224 NECP_PARSED_PARAMETERS_FIELD_REQUIRED_AGENT_TYPE)
3225
39037602
A
3226static bool
3227necp_update_client_result(proc_t proc,
0a7de745
A
3228 struct necp_fd_data *client_fd,
3229 struct necp_client *client,
3230 struct _necp_flow_defunct_list *defunct_list)
39037602
A
3231{
3232 struct necp_client_result_netagent netagent;
3233 struct necp_aggregate_result result;
5ba3f43e 3234 struct necp_client_parsed_parameters *parsed_parameters = NULL;
39037602 3235 u_int32_t flags = 0;
cb323159 3236 u_int32_t reason = 0;
39037602 3237
5ba3f43e 3238 NECP_CLIENT_ASSERT_LOCKED(client);
39037602 3239
5ba3f43e
A
3240 MALLOC(parsed_parameters, struct necp_client_parsed_parameters *, sizeof(*parsed_parameters), M_NECP, (M_WAITOK | M_ZERO));
3241 if (parsed_parameters == NULL) {
0a7de745
A
3242 NECPLOG0(LOG_ERR, "Failed to allocate parsed parameters");
3243 return FALSE;
5ba3f43e
A
3244 }
3245
3246 // Nexus flows will be brought back if they are still valid
3247 necp_client_mark_all_nonsocket_flows_as_invalid(client);
3248
3249 int error = necp_client_parse_parameters(client->parameters, (u_int32_t)client->parameters_length, parsed_parameters);
39037602 3250 if (error != 0) {
5ba3f43e 3251 FREE(parsed_parameters, M_NECP);
0a7de745 3252 return FALSE;
39037602
A
3253 }
3254
5ba3f43e
A
3255 // Update saved IP protocol
3256 client->ip_protocol = parsed_parameters->ip_protocol;
3257
d9a64523 3258 // Calculate the policy result
cb323159
A
3259 struct necp_client_endpoint v4_gateway = {};
3260 struct necp_client_endpoint v6_gateway = {};
ea3f0419
A
3261 uuid_t override_euuid;
3262 uuid_clear(override_euuid);
3263 if (!necp_calculate_client_result(proc, client, parsed_parameters, &result, &flags, &reason, &v4_gateway, &v6_gateway, &override_euuid)) {
d9a64523 3264 FREE(parsed_parameters, M_NECP);
0a7de745 3265 return FALSE;
d9a64523
A
3266 }
3267
3268 if (necp_update_parsed_parameters(parsed_parameters, &result)) {
3269 // Changed the parameters based on result, try again (only once)
ea3f0419 3270 if (!necp_calculate_client_result(proc, client, parsed_parameters, &result, &flags, &reason, &v4_gateway, &v6_gateway, &override_euuid)) {
5ba3f43e 3271 FREE(parsed_parameters, M_NECP);
0a7de745 3272 return FALSE;
39037602 3273 }
39037602
A
3274 }
3275
cb323159
A
3276 if ((parsed_parameters->flags & NECP_CLIENT_PARAMETER_FLAG_LISTENER) &&
3277 parsed_parameters->required_interface_index != IFSCOPE_NONE &&
3278 (parsed_parameters->valid_fields & NECP_PARSED_PARAMETERS_FIELD_REQUIRED_IF) == 0) {
3279 // Listener should not apply required interface index if
3280 parsed_parameters->required_interface_index = IFSCOPE_NONE;
3281 }
3282
5ba3f43e
A
3283 // Save the last policy id on the client
3284 client->policy_id = result.policy_id;
ea3f0419 3285 uuid_copy(client->override_euuid, override_euuid);
5ba3f43e
A
3286
3287 if ((parsed_parameters->flags & NECP_CLIENT_PARAMETER_FLAG_MULTIPATH) ||
ea3f0419 3288 (parsed_parameters->flags & NECP_CLIENT_PARAMETER_FLAG_BROWSE) ||
0a7de745
A
3289 ((parsed_parameters->flags & NECP_CLIENT_PARAMETER_FLAG_LISTENER) &&
3290 result.routing_result != NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED)) {
5ba3f43e
A
3291 client->allow_multiple_flows = TRUE;
3292 } else {
3293 client->allow_multiple_flows = FALSE;
3294 }
3295
39037602
A
3296 // If the original request was scoped, and the policy result matches, make sure the result is scoped
3297 if ((result.routing_result == NECP_KERNEL_POLICY_RESULT_NONE ||
0a7de745
A
3298 result.routing_result == NECP_KERNEL_POLICY_RESULT_PASS) &&
3299 result.routed_interface_index != IFSCOPE_NONE &&
3300 parsed_parameters->required_interface_index == result.routed_interface_index) {
39037602
A
3301 result.routing_result = NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED;
3302 result.routing_result_parameter.scoped_interface_index = result.routed_interface_index;
3303 }
3304
5ba3f43e 3305 if (defunct_list != NULL &&
0a7de745 3306 result.routing_result == NECP_KERNEL_POLICY_RESULT_DROP) {
5ba3f43e
A
3307 // If we are forced to drop the client, defunct it if it has flows
3308 necp_defunct_client_for_policy(client, defunct_list);
3309 }
3310
3311 // Recalculate flags
5ba3f43e
A
3312 if (parsed_parameters->flags & NECP_CLIENT_PARAMETER_FLAG_LISTENER) {
3313 // Listeners are valid as long as they aren't dropped
3314 if (result.routing_result != NECP_KERNEL_POLICY_RESULT_DROP) {
3315 flags |= NECP_CLIENT_RESULT_FLAG_SATISFIED;
3316 }
3317 } else if (result.routed_interface_index != 0) {
3318 // Clients without flows determine viability based on having some routable interface
3319 flags |= NECP_CLIENT_RESULT_FLAG_SATISFIED;
3320 }
3321
39037602
A
3322 bool updated = FALSE;
3323 u_int8_t *cursor = client->result;
5ba3f43e 3324 cursor = necp_buffer_write_tlv_if_different(cursor, NECP_CLIENT_RESULT_FLAGS, sizeof(flags), &flags, &updated, client->result, sizeof(client->result));
cb323159
A
3325 if (reason != 0) {
3326 cursor = necp_buffer_write_tlv_if_different(cursor, NECP_CLIENT_RESULT_REASON, sizeof(reason), &reason, &updated, client->result, sizeof(client->result));
3327 }
5ba3f43e 3328 cursor = necp_buffer_write_tlv_if_different(cursor, NECP_CLIENT_RESULT_CLIENT_ID, sizeof(uuid_t), client->client_id, &updated,
0a7de745 3329 client->result, sizeof(client->result));
5ba3f43e 3330 cursor = necp_buffer_write_tlv_if_different(cursor, NECP_CLIENT_RESULT_POLICY_RESULT, sizeof(result.routing_result), &result.routing_result, &updated,
0a7de745 3331 client->result, sizeof(client->result));
39037602 3332 if (result.routing_result_parameter.tunnel_interface_index != 0) {
5ba3f43e 3333 cursor = necp_buffer_write_tlv_if_different(cursor, NECP_CLIENT_RESULT_POLICY_RESULT_PARAMETER,
0a7de745
A
3334 sizeof(result.routing_result_parameter), &result.routing_result_parameter, &updated,
3335 client->result, sizeof(client->result));
39037602
A
3336 }
3337 if (result.filter_control_unit != 0) {
5ba3f43e 3338 cursor = necp_buffer_write_tlv_if_different(cursor, NECP_CLIENT_RESULT_FILTER_CONTROL_UNIT,
0a7de745
A
3339 sizeof(result.filter_control_unit), &result.filter_control_unit, &updated,
3340 client->result, sizeof(client->result));
39037602
A
3341 }
3342 if (result.routed_interface_index != 0) {
3343 u_int routed_interface_index = result.routed_interface_index;
3344 if (result.routing_result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL &&
cb323159 3345 (parsed_parameters->valid_fields & NECP_PARSED_PARAMETERS_REQUIRED_FIELDS) &&
0a7de745
A
3346 parsed_parameters->required_interface_index != IFSCOPE_NONE &&
3347 parsed_parameters->required_interface_index != result.routed_interface_index) {
5ba3f43e 3348 routed_interface_index = parsed_parameters->required_interface_index;
39037602
A
3349 }
3350
5ba3f43e 3351 cursor = necp_buffer_write_tlv_if_different(cursor, NECP_CLIENT_RESULT_INTERFACE_INDEX,
0a7de745
A
3352 sizeof(routed_interface_index), &routed_interface_index, &updated,
3353 client->result, sizeof(client->result));
5ba3f43e
A
3354 }
3355 if (client_fd && client_fd->flags & NECP_OPEN_FLAG_BACKGROUND) {
3356 u_int32_t effective_traffic_class = SO_TC_BK_SYS;
3357 cursor = necp_buffer_write_tlv_if_different(cursor, NECP_CLIENT_RESULT_EFFECTIVE_TRAFFIC_CLASS,
0a7de745
A
3358 sizeof(effective_traffic_class), &effective_traffic_class, &updated,
3359 client->result, sizeof(client->result));
5ba3f43e 3360 }
cb323159
A
3361
3362 if (client_fd->background) {
3363 bool has_assigned_flow = FALSE;
3364 struct necp_client_flow_registration *flow_registration = NULL;
3365 struct necp_client_flow *search_flow = NULL;
3366 RB_FOREACH(flow_registration, _necp_client_flow_tree, &client->flow_registrations) {
3367 LIST_FOREACH(search_flow, &flow_registration->flow_list, flow_chain) {
3368 if (search_flow->assigned) {
3369 has_assigned_flow = TRUE;
3370 break;
3371 }
3372 }
3373 }
3374
3375 if (has_assigned_flow) {
3376 u_int32_t background = client_fd->background;
3377 cursor = necp_buffer_write_tlv_if_different(cursor, NECP_CLIENT_RESULT_TRAFFIC_MGMT_BG,
3378 sizeof(background), &background, &updated,
3379 client->result, sizeof(client->result));
5ba3f43e 3380 }
39037602 3381 }
cb323159
A
3382
3383 bool write_v4_gateway = !necp_client_endpoint_is_unspecified(&v4_gateway);
3384 bool write_v6_gateway = !necp_client_endpoint_is_unspecified(&v6_gateway);
3385
5ba3f43e
A
3386 NECP_CLIENT_ROUTE_LOCK(client);
3387 if (client->current_route != NULL) {
3388 const u_int32_t route_mtu = get_maxmtu(client->current_route);
3389 if (route_mtu != 0) {
3390 cursor = necp_buffer_write_tlv_if_different(cursor, NECP_CLIENT_RESULT_EFFECTIVE_MTU,
0a7de745
A
3391 sizeof(route_mtu), &route_mtu, &updated,
3392 client->result, sizeof(client->result));
5ba3f43e 3393 }
cb323159
A
3394 bool has_remote_addr = parsed_parameters->valid_fields & NECP_PARSED_PARAMETERS_FIELD_REMOTE_ADDR;
3395 if (has_remote_addr && client->current_route->rt_gateway != NULL) {
3396 if (client->current_route->rt_gateway->sa_family == AF_INET) {
3397 write_v6_gateway = false;
3398 } else if (client->current_route->rt_gateway->sa_family == AF_INET6) {
3399 write_v4_gateway = false;
3400 }
3401 }
39037602 3402 }
5ba3f43e
A
3403 NECP_CLIENT_ROUTE_UNLOCK(client);
3404
cb323159
A
3405 if (write_v4_gateway) {
3406 cursor = necp_buffer_write_tlv_if_different(cursor, NECP_CLIENT_RESULT_GATEWAY,
3407 sizeof(struct necp_client_endpoint), &v4_gateway, &updated,
3408 client->result, sizeof(client->result));
3409 }
3410
3411 if (write_v6_gateway) {
3412 cursor = necp_buffer_write_tlv_if_different(cursor, NECP_CLIENT_RESULT_GATEWAY,
3413 sizeof(struct necp_client_endpoint), &v6_gateway, &updated,
3414 client->result, sizeof(client->result));
3415 }
3416
5ba3f43e
A
3417 if (result.mss_recommended != 0) {
3418 cursor = necp_buffer_write_tlv_if_different(cursor, NECP_CLIENT_RESULT_RECOMMENDED_MSS,
0a7de745
A
3419 sizeof(result.mss_recommended), &result.mss_recommended, &updated,
3420 client->result, sizeof(client->result));
5ba3f43e
A
3421 }
3422
39037602
A
3423 for (int i = 0; i < NECP_MAX_NETAGENTS; i++) {
3424 if (uuid_is_null(result.netagents[i])) {
3425 break;
3426 }
3427 uuid_copy(netagent.netagent_uuid, result.netagents[i]);
3428 netagent.generation = netagent_get_generation(netagent.netagent_uuid);
d9a64523 3429 if (necp_netagent_applies_to_client(client, parsed_parameters, &netagent.netagent_uuid, TRUE, 0, 0)) {
5ba3f43e 3430 cursor = necp_buffer_write_tlv_if_different(cursor, NECP_CLIENT_RESULT_NETAGENT, sizeof(netagent), &netagent, &updated,
0a7de745 3431 client->result, sizeof(client->result));
39037602
A
3432 }
3433 }
3434
3435 ifnet_head_lock_shared();
3436 ifnet_t direct_interface = NULL;
3437 ifnet_t delegate_interface = NULL;
3438 ifnet_t original_scoped_interface = NULL;
3439
813fb2f6 3440 if (result.routed_interface_index != IFSCOPE_NONE && result.routed_interface_index <= (u_int32_t)if_index) {
39037602 3441 direct_interface = ifindex2ifnet[result.routed_interface_index];
5ba3f43e 3442 } else if (parsed_parameters->required_interface_index != IFSCOPE_NONE &&
0a7de745 3443 parsed_parameters->required_interface_index <= (u_int32_t)if_index) {
39037602 3444 // If the request was scoped, but the route didn't match, still grab the agents
5ba3f43e 3445 direct_interface = ifindex2ifnet[parsed_parameters->required_interface_index];
39037602 3446 } else if (result.routed_interface_index == IFSCOPE_NONE &&
0a7de745
A
3447 result.routing_result == NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED &&
3448 result.routing_result_parameter.scoped_interface_index != IFSCOPE_NONE) {
39037602
A
3449 direct_interface = ifindex2ifnet[result.routing_result_parameter.scoped_interface_index];
3450 }
3451 if (direct_interface != NULL) {
3452 delegate_interface = direct_interface->if_delegated.ifp;
3453 }
3454 if (result.routing_result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL &&
cb323159 3455 (parsed_parameters->valid_fields & NECP_PARSED_PARAMETERS_REQUIRED_FIELDS) &&
0a7de745
A
3456 parsed_parameters->required_interface_index != IFSCOPE_NONE &&
3457 parsed_parameters->required_interface_index != result.routing_result_parameter.tunnel_interface_index &&
3458 parsed_parameters->required_interface_index <= (u_int32_t)if_index) {
5ba3f43e 3459 original_scoped_interface = ifindex2ifnet[parsed_parameters->required_interface_index];
39037602
A
3460 }
3461 // Add interfaces
3462 if (original_scoped_interface != NULL) {
3463 struct necp_client_result_interface interface_struct;
3464 interface_struct.index = original_scoped_interface->if_index;
3465 interface_struct.generation = ifnet_get_generation(original_scoped_interface);
5ba3f43e 3466 cursor = necp_buffer_write_tlv_if_different(cursor, NECP_CLIENT_RESULT_INTERFACE, sizeof(interface_struct), &interface_struct, &updated,
0a7de745 3467 client->result, sizeof(client->result));
39037602
A
3468 }
3469 if (direct_interface != NULL) {
3470 struct necp_client_result_interface interface_struct;
3471 interface_struct.index = direct_interface->if_index;
3472 interface_struct.generation = ifnet_get_generation(direct_interface);
5ba3f43e 3473 cursor = necp_buffer_write_tlv_if_different(cursor, NECP_CLIENT_RESULT_INTERFACE, sizeof(interface_struct), &interface_struct, &updated,
0a7de745 3474 client->result, sizeof(client->result));
9d749ea3
A
3475
3476 // Set the delta time since interface up/down
3477 struct timeval updown_delta = {};
3478 if (ifnet_updown_delta(direct_interface, &updown_delta) == 0) {
3479 u_int32_t delta = updown_delta.tv_sec;
3480 bool ignore_updated = FALSE;
3481 cursor = necp_buffer_write_tlv_if_different(cursor, NECP_CLIENT_RESULT_INTERFACE_TIME_DELTA,
0a7de745
A
3482 sizeof(delta), &delta, &ignore_updated,
3483 client->result, sizeof(client->result));
9d749ea3 3484 }
39037602
A
3485 }
3486 if (delegate_interface != NULL) {
3487 struct necp_client_result_interface interface_struct;
3488 interface_struct.index = delegate_interface->if_index;
3489 interface_struct.generation = ifnet_get_generation(delegate_interface);
5ba3f43e 3490 cursor = necp_buffer_write_tlv_if_different(cursor, NECP_CLIENT_RESULT_INTERFACE, sizeof(interface_struct), &interface_struct, &updated,
0a7de745 3491 client->result, sizeof(client->result));
5ba3f43e
A
3492 }
3493
3494 // Update multipath/listener interface flows
3495 if (parsed_parameters->flags & NECP_CLIENT_PARAMETER_FLAG_MULTIPATH) {
3496 // Get multipath interface options from ordered list
3497 struct ifnet *multi_interface = NULL;
3498 TAILQ_FOREACH(multi_interface, &ifnet_ordered_head, if_ordered_link) {
cb323159 3499 if (necp_ifnet_matches_parameters(multi_interface, parsed_parameters, 0, NULL, true, false)) {
5ba3f43e 3500 // Add multipath interface flows for kernel MPTCP
d9a64523 3501 necp_client_add_interface_option_if_needed(client, multi_interface->if_index,
0a7de745 3502 ifnet_get_generation(multi_interface), NULL);
5ba3f43e
A
3503
3504 // Add nexus agents for multipath
d9a64523 3505 necp_client_add_agent_interface_options(client, parsed_parameters, multi_interface);
5ba3f43e
A
3506 }
3507 }
cb323159
A
3508 } else if (parsed_parameters->flags & NECP_CLIENT_PARAMETER_FLAG_LISTENER) {
3509 if (result.routing_result == NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED) {
3510 if (direct_interface != NULL) {
3511 // If scoped, only listen on that interface
5ba3f43e 3512 // Add nexus agents for listeners
cb323159
A
3513 necp_client_add_agent_interface_options(client, parsed_parameters, direct_interface);
3514
3515 // Add interface option in case it is not a nexus
3516 necp_client_add_interface_option_if_needed(client, direct_interface->if_index,
3517 ifnet_get_generation(direct_interface), NULL);
3518 }
3519 } else {
3520 // Get listener interface options from global list
3521 struct ifnet *listen_interface = NULL;
3522 TAILQ_FOREACH(listen_interface, &ifnet_head, if_link) {
3523 if ((listen_interface->if_flags & (IFF_UP | IFF_RUNNING)) &&
3524 necp_ifnet_matches_parameters(listen_interface, parsed_parameters, 0, NULL, true, false)) {
3525 // Add nexus agents for listeners
3526 necp_client_add_agent_interface_options(client, parsed_parameters, listen_interface);
3527 }
5ba3f43e
A
3528 }
3529 }
ea3f0419
A
3530 } else if (parsed_parameters->flags & NECP_CLIENT_PARAMETER_FLAG_BROWSE) {
3531 if (result.routing_result == NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED) {
3532 if (direct_interface != NULL) {
3533 // Add browse option if it has an agent
3534 necp_client_add_browse_interface_options(client, parsed_parameters, direct_interface);
3535 }
3536 } else {
3537 // Get browse interface options from global list
3538 struct ifnet *browse_interface = NULL;
3539 TAILQ_FOREACH(browse_interface, &ifnet_head, if_link) {
3540 if (necp_ifnet_matches_parameters(browse_interface, parsed_parameters, 0, NULL, true, false)) {
3541 necp_client_add_browse_interface_options(client, parsed_parameters, browse_interface);
3542 }
3543 }
3544 }
39037602 3545 }
5ba3f43e 3546
39037602
A
3547 // Add agents
3548 if (original_scoped_interface != NULL) {
3549 ifnet_lock_shared(original_scoped_interface);
3550 if (original_scoped_interface->if_agentids != NULL) {
3551 for (u_int32_t i = 0; i < original_scoped_interface->if_agentcount; i++) {
3552 if (uuid_is_null(original_scoped_interface->if_agentids[i])) {
3553 continue;
3554 }
3555 uuid_copy(netagent.netagent_uuid, original_scoped_interface->if_agentids[i]);
3556 netagent.generation = netagent_get_generation(netagent.netagent_uuid);
d9a64523 3557 if (necp_netagent_applies_to_client(client, parsed_parameters, &netagent.netagent_uuid, FALSE,
0a7de745 3558 original_scoped_interface->if_index, ifnet_get_generation(original_scoped_interface))) {
5ba3f43e 3559 cursor = necp_buffer_write_tlv_if_different(cursor, NECP_CLIENT_RESULT_NETAGENT, sizeof(netagent), &netagent, &updated,
0a7de745 3560 client->result, sizeof(client->result));
39037602
A
3561 }
3562 }
3563 }
3564 ifnet_lock_done(original_scoped_interface);
3565 }
3566 if (direct_interface != NULL) {
3567 ifnet_lock_shared(direct_interface);
3568 if (direct_interface->if_agentids != NULL) {
3569 for (u_int32_t i = 0; i < direct_interface->if_agentcount; i++) {
3570 if (uuid_is_null(direct_interface->if_agentids[i])) {
3571 continue;
3572 }
3573 uuid_copy(netagent.netagent_uuid, direct_interface->if_agentids[i]);
3574 netagent.generation = netagent_get_generation(netagent.netagent_uuid);
d9a64523 3575 if (necp_netagent_applies_to_client(client, parsed_parameters, &netagent.netagent_uuid, TRUE,
0a7de745 3576 direct_interface->if_index, ifnet_get_generation(direct_interface))) {
5ba3f43e 3577 cursor = necp_buffer_write_tlv_if_different(cursor, NECP_CLIENT_RESULT_NETAGENT, sizeof(netagent), &netagent, &updated,
0a7de745 3578 client->result, sizeof(client->result));
39037602
A
3579 }
3580 }
3581 }
3582 ifnet_lock_done(direct_interface);
3583 }
3584 if (delegate_interface != NULL) {
3585 ifnet_lock_shared(delegate_interface);
3586 if (delegate_interface->if_agentids != NULL) {
3587 for (u_int32_t i = 0; i < delegate_interface->if_agentcount; i++) {
3588 if (uuid_is_null(delegate_interface->if_agentids[i])) {
3589 continue;
3590 }
3591 uuid_copy(netagent.netagent_uuid, delegate_interface->if_agentids[i]);
3592 netagent.generation = netagent_get_generation(netagent.netagent_uuid);
d9a64523 3593 if (necp_netagent_applies_to_client(client, parsed_parameters, &netagent.netagent_uuid, FALSE,
0a7de745 3594 delegate_interface->if_index, ifnet_get_generation(delegate_interface))) {
5ba3f43e 3595 cursor = necp_buffer_write_tlv_if_different(cursor, NECP_CLIENT_RESULT_NETAGENT, sizeof(netagent), &netagent, &updated,
0a7de745 3596 client->result, sizeof(client->result));
39037602
A
3597 }
3598 }
3599 }
3600 ifnet_lock_done(delegate_interface);
3601 }
3602 ifnet_head_done();
3603
d9a64523
A
3604 // Add interface options
3605 for (u_int32_t option_i = 0; option_i < client->interface_option_count; option_i++) {
3606 if (option_i < NECP_CLIENT_INTERFACE_OPTION_STATIC_COUNT) {
3607 struct necp_client_interface_option *option = &client->interface_options[option_i];
3608 cursor = necp_buffer_write_tlv_if_different(cursor, NECP_CLIENT_RESULT_INTERFACE_OPTION, sizeof(*option), option, &updated,
0a7de745 3609 client->result, sizeof(client->result));
d9a64523
A
3610 } else {
3611 struct necp_client_interface_option *option = &client->extra_interface_options[option_i - NECP_CLIENT_INTERFACE_OPTION_STATIC_COUNT];
3612 cursor = necp_buffer_write_tlv_if_different(cursor, NECP_CLIENT_RESULT_INTERFACE_OPTION, sizeof(*option), option, &updated,
0a7de745 3613 client->result, sizeof(client->result));
d9a64523
A
3614 }
3615 }
3616
39037602
A
3617 size_t new_result_length = (cursor - client->result);
3618 if (new_result_length != client->result_length) {
3619 client->result_length = new_result_length;
3620 updated = TRUE;
3621 }
5ba3f43e
A
3622
3623 // Update flow viability/flags
d9a64523 3624 if (necp_client_update_flows(proc, client, defunct_list)) {
5ba3f43e
A
3625 updated = TRUE;
3626 }
3627
39037602
A
3628 if (updated) {
3629 client->result_read = FALSE;
5ba3f43e 3630 necp_client_update_observer_update(client);
39037602
A
3631 }
3632
5ba3f43e 3633 FREE(parsed_parameters, M_NECP);
0a7de745 3634 return updated;
39037602
A
3635}
3636
5ba3f43e 3637static inline void
d9a64523 3638necp_defunct_client_fd_locked(struct necp_fd_data *client_fd, struct _necp_flow_defunct_list *defunct_list, struct proc *proc)
5ba3f43e 3639{
a39ff7e2 3640#pragma unused(proc)
5ba3f43e
A
3641 bool updated_result = FALSE;
3642 struct necp_client *client = NULL;
3643
3644 NECP_FD_ASSERT_LOCKED(client_fd);
a39ff7e2 3645
5ba3f43e 3646 RB_FOREACH(client, _necp_client_tree, &client_fd->clients) {
d9a64523
A
3647 struct necp_client_flow_registration *flow_registration = NULL;
3648
5ba3f43e 3649 NECP_CLIENT_LOCK(client);
5ba3f43e 3650
d9a64523
A
3651 // Prepare close events to be sent to the nexus to effectively remove the flows
3652 struct necp_client_flow *search_flow = NULL;
3653 RB_FOREACH(flow_registration, _necp_client_flow_tree, &client->flow_registrations) {
3654 LIST_FOREACH(search_flow, &flow_registration->flow_list, flow_chain) {
5ba3f43e 3655 if (search_flow->nexus &&
0a7de745 3656 !uuid_is_null(search_flow->u.nexus_agent)) {
5ba3f43e 3657 // Sleeping alloc won't fail; copy only what's necessary
cb323159 3658 struct necp_flow_defunct *flow_defunct = _MALLOC(sizeof(struct necp_flow_defunct), M_NECP, M_WAITOK | M_ZERO);
d9a64523
A
3659 uuid_copy(flow_defunct->nexus_agent, search_flow->u.nexus_agent);
3660 uuid_copy(flow_defunct->flow_id, ((flow_registration->flags & NECP_CLIENT_FLOW_FLAGS_USE_CLIENT_ID) ?
0a7de745
A
3661 client->client_id :
3662 flow_registration->registration_id));
d9a64523
A
3663 flow_defunct->proc_pid = client->proc_pid;
3664 flow_defunct->agent_handle = client->agent_handle;
cb323159 3665 flow_defunct->flags = flow_registration->flags;
5ba3f43e 3666 // Add to the list provided by caller
d9a64523
A
3667 LIST_INSERT_HEAD(defunct_list, flow_defunct, chain);
3668
3669 flow_registration->defunct = true;
3670 flow_registration->flow_result_read = false;
3671 updated_result = true;
5ba3f43e
A
3672 }
3673 }
3674 }
3675 NECP_CLIENT_UNLOCK(client);
3676 }
a39ff7e2
A
3677
3678
5ba3f43e
A
3679 if (updated_result) {
3680 necp_fd_notify(client_fd, true);
3681 }
3682}
3683
3684static inline void
3685necp_update_client_fd_locked(struct necp_fd_data *client_fd,
0a7de745
A
3686 proc_t proc,
3687 struct _necp_flow_defunct_list *defunct_list)
5ba3f43e
A
3688{
3689 struct necp_client *client = NULL;
3690 bool updated_result = FALSE;
3691 NECP_FD_ASSERT_LOCKED(client_fd);
3692 RB_FOREACH(client, _necp_client_tree, &client_fd->clients) {
3693 NECP_CLIENT_LOCK(client);
3694 if (necp_update_client_result(proc, client_fd, client, defunct_list)) {
3695 updated_result = TRUE;
3696 }
3697 NECP_CLIENT_UNLOCK(client);
3698 }
3699 if (updated_result) {
3700 necp_fd_notify(client_fd, true);
3701 }
3702}
3703
3704
39037602
A
3705static void
3706necp_update_all_clients_callout(__unused thread_call_param_t dummy,
0a7de745 3707 __unused thread_call_param_t arg)
39037602 3708{
39037602
A
3709 struct necp_fd_data *client_fd = NULL;
3710
d9a64523 3711 struct _necp_flow_defunct_list defunct_list;
5ba3f43e
A
3712 LIST_INIT(&defunct_list);
3713
3714 NECP_FD_LIST_LOCK_SHARED();
39037602
A
3715
3716 LIST_FOREACH(client_fd, &necp_fd_list, chain) {
39037602 3717 proc_t proc = proc_find(client_fd->proc_pid);
5ba3f43e 3718 if (proc == PROC_NULL) {
39037602
A
3719 continue;
3720 }
3721
5ba3f43e
A
3722 // Update all clients on one fd
3723 NECP_FD_LOCK(client_fd);
3724 necp_update_client_fd_locked(client_fd, proc, &defunct_list);
3725 NECP_FD_UNLOCK(client_fd);
3726
3727 proc_rele(proc);
3728 proc = PROC_NULL;
3729 }
3730
3731 NECP_FD_LIST_UNLOCK();
3732
3733 // Handle the case in which some clients became newly defunct
3734 if (!LIST_EMPTY(&defunct_list)) {
d9a64523
A
3735 struct necp_flow_defunct *flow_defunct = NULL;
3736 struct necp_flow_defunct *temp_flow_defunct = NULL;
5ba3f43e
A
3737
3738 // For each newly defunct client, send a message to the nexus to remove the flow
d9a64523
A
3739 LIST_FOREACH_SAFE(flow_defunct, &defunct_list, chain, temp_flow_defunct) {
3740 if (!uuid_is_null(flow_defunct->nexus_agent)) {
cb323159
A
3741 u_int8_t message_type = NETAGENT_MESSAGE_TYPE_ABORT_NEXUS;
3742 if (((flow_defunct->flags & NECP_CLIENT_FLOW_FLAGS_BROWSE) ||
3743 (flow_defunct->flags & NECP_CLIENT_FLOW_FLAGS_RESOLVE)) &&
3744 !(flow_defunct->flags & NECP_CLIENT_FLOW_FLAGS_ALLOW_NEXUS)) {
3745 message_type = NETAGENT_MESSAGE_TYPE_CLIENT_UNASSERT;
3746 }
3747 int netagent_error = netagent_client_message_with_params(flow_defunct->nexus_agent,
0a7de745
A
3748 flow_defunct->flow_id,
3749 flow_defunct->proc_pid,
3750 flow_defunct->agent_handle,
cb323159
A
3751 message_type,
3752 flow_defunct->has_close_parameters ? &flow_defunct->close_parameters : NULL,
3753 NULL, 0);
5ba3f43e 3754 if (netagent_error != 0) {
0a7de745
A
3755 char namebuf[MAXCOMLEN + 1];
3756 (void) strlcpy(namebuf, "unknown", sizeof(namebuf));
3757 proc_name(flow_defunct->proc_pid, namebuf, sizeof(namebuf));
d9a64523 3758 NECPLOG((netagent_error == ENOENT ? LOG_DEBUG : LOG_ERR), "necp_update_client abort nexus error (%d) for pid %d %s", netagent_error, flow_defunct->proc_pid, namebuf);
5ba3f43e 3759 }
39037602 3760 }
d9a64523
A
3761 LIST_REMOVE(flow_defunct, chain);
3762 FREE(flow_defunct, M_NECP);
39037602 3763 }
5ba3f43e
A
3764 }
3765 ASSERT(LIST_EMPTY(&defunct_list));
3766}
3767
3768void
3769necp_update_all_clients(void)
cb323159
A
3770{
3771 necp_update_all_clients_immediately_if_needed(false);
3772}
3773
3774void
3775necp_update_all_clients_immediately_if_needed(bool should_update_immediately)
5ba3f43e
A
3776{
3777 if (necp_client_update_tcall == NULL) {
3778 // Don't try to update clients if the module is not initialized
3779 return;
3780 }
3781
3782 uint64_t deadline = 0;
3783 uint64_t leeway = 0;
cb323159
A
3784
3785 uint32_t timeout_to_use = necp_timeout_microseconds;
3786 uint32_t leeway_to_use = necp_timeout_leeway_microseconds;
3787 if (should_update_immediately) {
3788 timeout_to_use = 1000 * 10; // 10ms
3789 leeway_to_use = 1000 * 10; // 10ms;
3790 }
3791
3792 clock_interval_to_deadline(timeout_to_use, NSEC_PER_USEC, &deadline);
3793 clock_interval_to_absolutetime_interval(leeway_to_use, NSEC_PER_USEC, &leeway);
5ba3f43e
A
3794
3795 thread_call_enter_delayed_with_leeway(necp_client_update_tcall, NULL,
0a7de745 3796 deadline, leeway, THREAD_CALL_DELAY_LEEWAY);
5ba3f43e
A
3797}
3798
cb323159 3799bool
5ba3f43e 3800necp_set_client_as_background(proc_t proc,
0a7de745
A
3801 struct fileproc *fp,
3802 bool background)
5ba3f43e 3803{
5ba3f43e
A
3804 if (proc == PROC_NULL) {
3805 NECPLOG0(LOG_ERR, "NULL proc");
cb323159 3806 return FALSE;
5ba3f43e
A
3807 }
3808
3809 if (fp == NULL) {
3810 NECPLOG0(LOG_ERR, "NULL fp");
cb323159 3811 return FALSE;
5ba3f43e
A
3812 }
3813
3814 struct necp_fd_data *client_fd = (struct necp_fd_data *)fp->f_fglob->fg_data;
3815 if (client_fd == NULL) {
3816 NECPLOG0(LOG_ERR, "Could not find client structure for backgrounded client");
cb323159 3817 return FALSE;
5ba3f43e
A
3818 }
3819
3820 if (client_fd->necp_fd_type != necp_fd_type_client) {
3821 // Not a client fd, ignore
3822 NECPLOG0(LOG_ERR, "Not a client fd, ignore");
cb323159 3823 return FALSE;
5ba3f43e
A
3824 }
3825
cb323159 3826 client_fd->background = background;
5ba3f43e 3827
cb323159 3828 return TRUE;
5ba3f43e
A
3829}
3830
3831void
a39ff7e2
A
3832necp_fd_memstatus(proc_t proc, uint32_t status,
3833 struct necp_fd_data *client_fd)
5ba3f43e 3834{
a39ff7e2
A
3835#pragma unused(proc, status, client_fd)
3836 ASSERT(proc != PROC_NULL);
3837 ASSERT(client_fd != NULL);
5ba3f43e 3838
a39ff7e2
A
3839 // Nothing to reap for the process or client for now,
3840 // but this is where we would trigger that in future.
3841}
5ba3f43e 3842
a39ff7e2
A
3843void
3844necp_fd_defunct(proc_t proc, struct necp_fd_data *client_fd)
3845{
d9a64523 3846 struct _necp_flow_defunct_list defunct_list;
39037602 3847
a39ff7e2
A
3848 ASSERT(proc != PROC_NULL);
3849 ASSERT(client_fd != NULL);
39037602 3850
5ba3f43e
A
3851 if (client_fd->necp_fd_type != necp_fd_type_client) {
3852 // Not a client fd, ignore
39037602
A
3853 return;
3854 }
3855
5ba3f43e
A
3856 // Our local temporary list
3857 LIST_INIT(&defunct_list);
39037602 3858
5ba3f43e
A
3859 // Need to hold lock so ntstats defunct the same set of clients
3860 NECP_FD_LOCK(client_fd);
a39ff7e2 3861 necp_defunct_client_fd_locked(client_fd, &defunct_list, proc);
5ba3f43e
A
3862 NECP_FD_UNLOCK(client_fd);
3863
3864 if (!LIST_EMPTY(&defunct_list)) {
d9a64523
A
3865 struct necp_flow_defunct *flow_defunct = NULL;
3866 struct necp_flow_defunct *temp_flow_defunct = NULL;
5ba3f43e
A
3867
3868 // For each defunct client, remove flow from the nexus
d9a64523
A
3869 LIST_FOREACH_SAFE(flow_defunct, &defunct_list, chain, temp_flow_defunct) {
3870 if (!uuid_is_null(flow_defunct->nexus_agent)) {
cb323159
A
3871 u_int8_t message_type = NETAGENT_MESSAGE_TYPE_ABORT_NEXUS;
3872 if (((flow_defunct->flags & NECP_CLIENT_FLOW_FLAGS_BROWSE) ||
3873 (flow_defunct->flags & NECP_CLIENT_FLOW_FLAGS_RESOLVE)) &&
3874 !(flow_defunct->flags & NECP_CLIENT_FLOW_FLAGS_ALLOW_NEXUS)) {
3875 message_type = NETAGENT_MESSAGE_TYPE_CLIENT_UNASSERT;
3876 }
3877 int netagent_error = netagent_client_message_with_params(flow_defunct->nexus_agent,
0a7de745
A
3878 flow_defunct->flow_id,
3879 flow_defunct->proc_pid,
3880 flow_defunct->agent_handle,
cb323159
A
3881 message_type,
3882 flow_defunct->has_close_parameters ? &flow_defunct->close_parameters : NULL,
3883 NULL, 0);
5ba3f43e
A
3884 if (netagent_error != 0) {
3885 NECPLOG((netagent_error == ENOENT ? LOG_DEBUG : LOG_ERR), "necp_defunct_client abort nexus error (%d)", netagent_error);
3886 }
3887 }
d9a64523
A
3888 LIST_REMOVE(flow_defunct, chain);
3889 FREE(flow_defunct, M_NECP);
5ba3f43e
A
3890 }
3891 }
3892 ASSERT(LIST_EMPTY(&defunct_list));
39037602
A
3893}
3894
3895static void
3896necp_client_remove_agent_from_result(struct necp_client *client, uuid_t netagent_uuid)
3897{
3898 size_t offset = 0;
3899
3900 u_int8_t *result_buffer = client->result;
5ba3f43e 3901 while ((offset + sizeof(struct necp_tlv_header)) <= client->result_length) {
39037602
A
3902 u_int8_t type = necp_buffer_get_tlv_type(result_buffer, offset);
3903 u_int32_t length = necp_buffer_get_tlv_length(result_buffer, offset);
3904
5ba3f43e 3905 size_t tlv_total_length = (sizeof(struct necp_tlv_header) + length);
39037602 3906 if (type == NECP_CLIENT_RESULT_NETAGENT &&
0a7de745
A
3907 length == sizeof(struct necp_client_result_netagent) &&
3908 (offset + tlv_total_length) <= client->result_length) {
39037602 3909 struct necp_client_result_netagent *value = ((struct necp_client_result_netagent *)(void *)
0a7de745 3910 necp_buffer_get_tlv_value(result_buffer, offset, NULL));
39037602
A
3911 if (uuid_compare(value->netagent_uuid, netagent_uuid) == 0) {
3912 // Found a netagent to remove
3913 // Shift bytes down to remove the tlv, and adjust total length
3914 // Don't adjust the current offset
3915 memmove(result_buffer + offset,
0a7de745
A
3916 result_buffer + offset + tlv_total_length,
3917 client->result_length - (offset + tlv_total_length));
39037602 3918 client->result_length -= tlv_total_length;
5ba3f43e 3919 memset(result_buffer + client->result_length, 0, sizeof(client->result) - client->result_length);
39037602
A
3920 continue;
3921 }
3922 }
3923
3924 offset += tlv_total_length;
3925 }
3926}
3927
3928void
d9a64523 3929necp_force_update_client(uuid_t client_id, uuid_t remove_netagent_uuid, u_int32_t agent_generation)
39037602
A
3930{
3931 struct necp_fd_data *client_fd = NULL;
3932
5ba3f43e 3933 NECP_FD_LIST_LOCK_SHARED();
39037602
A
3934
3935 LIST_FOREACH(client_fd, &necp_fd_list, chain) {
3936 bool updated_result = FALSE;
5ba3f43e
A
3937 NECP_FD_LOCK(client_fd);
3938 struct necp_client *client = necp_client_fd_find_client_and_lock(client_fd, client_id);
3939 if (client != NULL) {
d9a64523
A
3940 client->failed_trigger_agent.generation = agent_generation;
3941 uuid_copy(client->failed_trigger_agent.netagent_uuid, remove_netagent_uuid);
5ba3f43e
A
3942 if (!uuid_is_null(remove_netagent_uuid)) {
3943 necp_client_remove_agent_from_result(client, remove_netagent_uuid);
39037602 3944 }
d9a64523 3945 client->result_read = FALSE;
5ba3f43e
A
3946 // Found the client, break
3947 updated_result = TRUE;
3948 NECP_CLIENT_UNLOCK(client);
39037602
A
3949 }
3950 if (updated_result) {
3951 necp_fd_notify(client_fd, true);
3952 }
5ba3f43e 3953 NECP_FD_UNLOCK(client_fd);
39037602
A
3954 if (updated_result) {
3955 // Found the client, break
3956 break;
3957 }
3958 }
3959
5ba3f43e 3960 NECP_FD_LIST_UNLOCK();
39037602
A
3961}
3962
5ba3f43e 3963
39037602
A
3964/// Interface matching
3965
0a7de745
A
3966#define NECP_PARSED_PARAMETERS_INTERESTING_IFNET_FIELDS (NECP_PARSED_PARAMETERS_FIELD_LOCAL_ADDR | \
3967 NECP_PARSED_PARAMETERS_FIELD_PROHIBITED_IF | \
3968 NECP_PARSED_PARAMETERS_FIELD_REQUIRED_IFTYPE | \
3969 NECP_PARSED_PARAMETERS_FIELD_PROHIBITED_IFTYPE | \
3970 NECP_PARSED_PARAMETERS_FIELD_REQUIRED_AGENT | \
3971 NECP_PARSED_PARAMETERS_FIELD_PROHIBITED_AGENT | \
3972 NECP_PARSED_PARAMETERS_FIELD_PREFERRED_AGENT | \
3973 NECP_PARSED_PARAMETERS_FIELD_AVOIDED_AGENT | \
3974 NECP_PARSED_PARAMETERS_FIELD_REQUIRED_AGENT_TYPE | \
3975 NECP_PARSED_PARAMETERS_FIELD_PROHIBITED_AGENT_TYPE | \
3976 NECP_PARSED_PARAMETERS_FIELD_PREFERRED_AGENT_TYPE | \
3977 NECP_PARSED_PARAMETERS_FIELD_AVOIDED_AGENT_TYPE)
3978
3979#define NECP_PARSED_PARAMETERS_SCOPED_FIELDS (NECP_PARSED_PARAMETERS_FIELD_LOCAL_ADDR | \
3980 NECP_PARSED_PARAMETERS_FIELD_REQUIRED_IFTYPE | \
3981 NECP_PARSED_PARAMETERS_FIELD_REQUIRED_AGENT | \
3982 NECP_PARSED_PARAMETERS_FIELD_PREFERRED_AGENT | \
0a7de745 3983 NECP_PARSED_PARAMETERS_FIELD_REQUIRED_AGENT_TYPE | \
cb323159 3984 NECP_PARSED_PARAMETERS_FIELD_PREFERRED_AGENT_TYPE)
0a7de745
A
3985
3986#define NECP_PARSED_PARAMETERS_SCOPED_IFNET_FIELDS (NECP_PARSED_PARAMETERS_FIELD_LOCAL_ADDR | \
3987 NECP_PARSED_PARAMETERS_FIELD_REQUIRED_IFTYPE)
3988
3989#define NECP_PARSED_PARAMETERS_PREFERRED_FIELDS (NECP_PARSED_PARAMETERS_FIELD_PREFERRED_AGENT | \
3990 NECP_PARSED_PARAMETERS_FIELD_AVOIDED_AGENT | \
3991 NECP_PARSED_PARAMETERS_FIELD_PREFERRED_AGENT_TYPE | \
3992 NECP_PARSED_PARAMETERS_FIELD_AVOIDED_AGENT_TYPE)
39037602
A
3993
3994static bool
3995necp_ifnet_matches_type(struct ifnet *ifp, u_int8_t interface_type, bool check_delegates)
3996{
3997 struct ifnet *check_ifp = ifp;
3998 while (check_ifp) {
3999 if (if_functional_type(check_ifp, TRUE) == interface_type) {
0a7de745 4000 return TRUE;
39037602
A
4001 }
4002 if (!check_delegates) {
4003 break;
4004 }
4005 check_ifp = check_ifp->if_delegated.ifp;
39037602 4006 }
0a7de745 4007 return FALSE;
39037602
A
4008}
4009
4010static bool
4011necp_ifnet_matches_name(struct ifnet *ifp, const char *interface_name, bool check_delegates)
4012{
4013 struct ifnet *check_ifp = ifp;
4014 while (check_ifp) {
4015 if (strncmp(check_ifp->if_xname, interface_name, IFXNAMSIZ) == 0) {
0a7de745 4016 return TRUE;
39037602
A
4017 }
4018 if (!check_delegates) {
4019 break;
4020 }
4021 check_ifp = check_ifp->if_delegated.ifp;
4022 }
0a7de745 4023 return FALSE;
39037602
A
4024}
4025
4026static bool
4027necp_ifnet_matches_agent(struct ifnet *ifp, uuid_t *agent_uuid, bool check_delegates)
4028{
4029 struct ifnet *check_ifp = ifp;
4030
4031 while (check_ifp != NULL) {
4032 ifnet_lock_shared(check_ifp);
4033 if (check_ifp->if_agentids != NULL) {
4034 for (u_int32_t index = 0; index < check_ifp->if_agentcount; index++) {
4035 if (uuid_compare(check_ifp->if_agentids[index], *agent_uuid) == 0) {
4036 ifnet_lock_done(check_ifp);
0a7de745 4037 return TRUE;
39037602
A
4038 }
4039 }
4040 }
4041 ifnet_lock_done(check_ifp);
4042
4043 if (!check_delegates) {
4044 break;
4045 }
4046 check_ifp = check_ifp->if_delegated.ifp;
4047 }
0a7de745 4048 return FALSE;
39037602
A
4049}
4050
4051static bool
d9a64523 4052necp_ifnet_matches_agent_type(struct ifnet *ifp, const char *agent_domain, const char *agent_type, bool check_delegates)
39037602
A
4053{
4054 struct ifnet *check_ifp = ifp;
4055
4056 while (check_ifp != NULL) {
4057 ifnet_lock_shared(check_ifp);
4058 if (check_ifp->if_agentids != NULL) {
4059 for (u_int32_t index = 0; index < check_ifp->if_agentcount; index++) {
4060 if (uuid_is_null(check_ifp->if_agentids[index])) {
4061 continue;
4062 }
4063
4064 char if_agent_domain[NETAGENT_DOMAINSIZE] = { 0 };
4065 char if_agent_type[NETAGENT_TYPESIZE] = { 0 };
4066
4067 if (netagent_get_agent_domain_and_type(check_ifp->if_agentids[index], if_agent_domain, if_agent_type)) {
d9a64523
A
4068 if (necp_agent_types_match(agent_domain, agent_type, if_agent_domain, if_agent_type)) {
4069 ifnet_lock_done(check_ifp);
0a7de745 4070 return TRUE;
d9a64523 4071 }
39037602
A
4072 }
4073 }
4074 }
4075 ifnet_lock_done(check_ifp);
4076
4077 if (!check_delegates) {
4078 break;
4079 }
4080 check_ifp = check_ifp->if_delegated.ifp;
4081 }
0a7de745 4082 return FALSE;
39037602
A
4083}
4084
4085static bool
4086necp_ifnet_matches_local_address(struct ifnet *ifp, struct sockaddr *sa)
4087{
4088 struct ifaddr *ifa = NULL;
4089 bool matched_local_address = FALSE;
4090
4091 // Transform sa into the ifaddr form
4092 // IPv6 Scope IDs are always embedded in the ifaddr list
4093 struct sockaddr_storage address;
4094 u_int ifscope = IFSCOPE_NONE;
4095 (void)sa_copy(sa, &address, &ifscope);
4096 SIN(&address)->sin_port = 0;
4097 if (address.ss_family == AF_INET6) {
4098 SIN6(&address)->sin6_scope_id = 0;
4099 }
4100
4101 ifa = ifa_ifwithaddr_scoped_locked((struct sockaddr *)&address, ifp->if_index);
4102 matched_local_address = (ifa != NULL);
4103
4104 if (ifa) {
4105 ifaddr_release(ifa);
4106 }
4107
0a7de745 4108 return matched_local_address;
39037602
A
4109}
4110
5ba3f43e
A
4111static bool
4112necp_interface_type_is_primary_eligible(u_int8_t interface_type)
4113{
4114 switch (interface_type) {
0a7de745
A
4115 // These types can never be primary, so a client requesting these types is allowed
4116 // to match an interface that isn't currently eligible to be primary (has default
4117 // route, dns, etc)
4118 case IFRTYPE_FUNCTIONAL_WIFI_AWDL:
4119 case IFRTYPE_FUNCTIONAL_INTCOPROC:
4120 return false;
4121 default:
4122 break;
5ba3f43e
A
4123 }
4124 return true;
4125}
4126
4127#define NECP_IFP_IS_ON_ORDERED_LIST(_ifp) ((_ifp)->if_ordered_link.tqe_next != NULL || (_ifp)->if_ordered_link.tqe_prev != NULL)
4128
d9a64523
A
4129// Secondary interface flag indicates that the interface is being
4130// used for multipath or a listener as an extra path
39037602
A
4131static bool
4132necp_ifnet_matches_parameters(struct ifnet *ifp,
0a7de745 4133 struct necp_client_parsed_parameters *parsed_parameters,
cb323159 4134 u_int32_t override_flags,
0a7de745 4135 u_int32_t *preferred_count,
cb323159
A
4136 bool secondary_interface,
4137 bool require_scoped_field)
39037602 4138{
cb323159
A
4139 bool matched_some_scoped_field = FALSE;
4140
39037602
A
4141 if (preferred_count) {
4142 *preferred_count = 0;
4143 }
4144
cb323159
A
4145 if (parsed_parameters->valid_fields & NECP_PARSED_PARAMETERS_FIELD_REQUIRED_IF) {
4146 if (parsed_parameters->required_interface_index != ifp->if_index) {
4147 return FALSE;
4148 }
4149 }
4150
39037602
A
4151 if (parsed_parameters->valid_fields & NECP_PARSED_PARAMETERS_FIELD_LOCAL_ADDR) {
4152 if (!necp_ifnet_matches_local_address(ifp, &parsed_parameters->local_addr.sa)) {
0a7de745 4153 return FALSE;
39037602 4154 }
cb323159
A
4155 if (require_scoped_field) {
4156 matched_some_scoped_field = TRUE;
4157 }
39037602
A
4158 }
4159
5ba3f43e 4160 if (parsed_parameters->valid_fields & NECP_PARSED_PARAMETERS_FIELD_FLAGS) {
cb323159
A
4161 if (override_flags != 0) {
4162 if ((override_flags & NECP_CLIENT_PARAMETER_FLAG_PROHIBIT_EXPENSIVE) &&
4163 IFNET_IS_EXPENSIVE(ifp)) {
4164 return FALSE;
4165 }
4166 if ((override_flags & NECP_CLIENT_PARAMETER_FLAG_PROHIBIT_CONSTRAINED) &&
4167 IFNET_IS_CONSTRAINED(ifp)) {
4168 return FALSE;
4169 }
4170 } else {
4171 if ((parsed_parameters->flags & NECP_CLIENT_PARAMETER_FLAG_PROHIBIT_EXPENSIVE) &&
4172 IFNET_IS_EXPENSIVE(ifp)) {
4173 return FALSE;
4174 }
4175 if ((parsed_parameters->flags & NECP_CLIENT_PARAMETER_FLAG_PROHIBIT_CONSTRAINED) &&
4176 IFNET_IS_CONSTRAINED(ifp)) {
4177 return FALSE;
4178 }
39037602
A
4179 }
4180 }
4181
d9a64523 4182 if ((!secondary_interface || // Enforce interface type if this is the primary interface
0a7de745
A
4183 !(parsed_parameters->valid_fields & NECP_PARSED_PARAMETERS_FIELD_FLAGS) || // or if there are no flags
4184 !(parsed_parameters->flags & NECP_CLIENT_PARAMETER_FLAG_ONLY_PRIMARY_REQUIRES_TYPE)) && // or if the flags don't give an exception
5ba3f43e 4185 (parsed_parameters->valid_fields & NECP_PARSED_PARAMETERS_FIELD_REQUIRED_IFTYPE) &&
0a7de745
A
4186 !necp_ifnet_matches_type(ifp, parsed_parameters->required_interface_type, FALSE)) {
4187 return FALSE;
5ba3f43e
A
4188 }
4189
cb323159
A
4190 if (parsed_parameters->valid_fields & NECP_PARSED_PARAMETERS_FIELD_REQUIRED_IFTYPE) {
4191 if (require_scoped_field) {
4192 matched_some_scoped_field = TRUE;
4193 }
4194 }
4195
39037602 4196 if (parsed_parameters->valid_fields & NECP_PARSED_PARAMETERS_FIELD_PROHIBITED_IFTYPE) {
cb323159 4197 for (int i = 0; i < NECP_MAX_INTERFACE_PARAMETERS; i++) {
39037602
A
4198 if (parsed_parameters->prohibited_interface_types[i] == 0) {
4199 break;
4200 }
4201
4202 if (necp_ifnet_matches_type(ifp, parsed_parameters->prohibited_interface_types[i], TRUE)) {
0a7de745 4203 return FALSE;
39037602
A
4204 }
4205 }
4206 }
4207
4208 if (parsed_parameters->valid_fields & NECP_PARSED_PARAMETERS_FIELD_PROHIBITED_IF) {
cb323159 4209 for (int i = 0; i < NECP_MAX_INTERFACE_PARAMETERS; i++) {
39037602
A
4210 if (strlen(parsed_parameters->prohibited_interfaces[i]) == 0) {
4211 break;
4212 }
4213
4214 if (necp_ifnet_matches_name(ifp, parsed_parameters->prohibited_interfaces[i], TRUE)) {
0a7de745 4215 return FALSE;
39037602
A
4216 }
4217 }
4218 }
4219
4220 if (parsed_parameters->valid_fields & NECP_PARSED_PARAMETERS_FIELD_REQUIRED_AGENT) {
cb323159 4221 for (int i = 0; i < NECP_MAX_AGENT_PARAMETERS; i++) {
39037602
A
4222 if (uuid_is_null(parsed_parameters->required_netagents[i])) {
4223 break;
4224 }
4225
4226 if (!necp_ifnet_matches_agent(ifp, &parsed_parameters->required_netagents[i], FALSE)) {
0a7de745 4227 return FALSE;
39037602 4228 }
cb323159
A
4229
4230 if (require_scoped_field) {
4231 matched_some_scoped_field = TRUE;
4232 }
39037602
A
4233 }
4234 }
4235
4236 if (parsed_parameters->valid_fields & NECP_PARSED_PARAMETERS_FIELD_PROHIBITED_AGENT) {
cb323159 4237 for (int i = 0; i < NECP_MAX_AGENT_PARAMETERS; i++) {
39037602
A
4238 if (uuid_is_null(parsed_parameters->prohibited_netagents[i])) {
4239 break;
4240 }
4241
4242 if (necp_ifnet_matches_agent(ifp, &parsed_parameters->prohibited_netagents[i], TRUE)) {
0a7de745 4243 return FALSE;
39037602
A
4244 }
4245 }
4246 }
4247
4248 if (parsed_parameters->valid_fields & NECP_PARSED_PARAMETERS_FIELD_REQUIRED_AGENT_TYPE) {
cb323159 4249 for (int i = 0; i < NECP_MAX_AGENT_PARAMETERS; i++) {
39037602 4250 if (strlen(parsed_parameters->required_netagent_types[i].netagent_domain) == 0 &&
0a7de745 4251 strlen(parsed_parameters->required_netagent_types[i].netagent_type) == 0) {
39037602
A
4252 break;
4253 }
4254
d9a64523 4255 if (!necp_ifnet_matches_agent_type(ifp, parsed_parameters->required_netagent_types[i].netagent_domain, parsed_parameters->required_netagent_types[i].netagent_type, FALSE)) {
0a7de745 4256 return FALSE;
39037602 4257 }
cb323159
A
4258
4259 if (require_scoped_field) {
4260 matched_some_scoped_field = TRUE;
4261 }
39037602
A
4262 }
4263 }
4264
4265 if (parsed_parameters->valid_fields & NECP_PARSED_PARAMETERS_FIELD_PROHIBITED_AGENT_TYPE) {
cb323159 4266 for (int i = 0; i < NECP_MAX_AGENT_PARAMETERS; i++) {
39037602 4267 if (strlen(parsed_parameters->prohibited_netagent_types[i].netagent_domain) == 0 &&
0a7de745 4268 strlen(parsed_parameters->prohibited_netagent_types[i].netagent_type) == 0) {
39037602
A
4269 break;
4270 }
4271
d9a64523 4272 if (necp_ifnet_matches_agent_type(ifp, parsed_parameters->prohibited_netagent_types[i].netagent_domain, parsed_parameters->prohibited_netagent_types[i].netagent_type, TRUE)) {
0a7de745 4273 return FALSE;
39037602
A
4274 }
4275 }
4276 }
4277
4278 // Checked preferred properties
4279 if (preferred_count) {
4280 if (parsed_parameters->valid_fields & NECP_PARSED_PARAMETERS_FIELD_PREFERRED_AGENT) {
cb323159 4281 for (int i = 0; i < NECP_MAX_AGENT_PARAMETERS; i++) {
39037602
A
4282 if (uuid_is_null(parsed_parameters->preferred_netagents[i])) {
4283 break;
4284 }
4285
4286 if (necp_ifnet_matches_agent(ifp, &parsed_parameters->preferred_netagents[i], TRUE)) {
4287 (*preferred_count)++;
cb323159
A
4288 if (require_scoped_field) {
4289 matched_some_scoped_field = TRUE;
4290 }
39037602
A
4291 }
4292 }
4293 }
4294
4295 if (parsed_parameters->valid_fields & NECP_PARSED_PARAMETERS_FIELD_PREFERRED_AGENT_TYPE) {
cb323159 4296 for (int i = 0; i < NECP_MAX_AGENT_PARAMETERS; i++) {
39037602 4297 if (strlen(parsed_parameters->preferred_netagent_types[i].netagent_domain) == 0 &&
0a7de745 4298 strlen(parsed_parameters->preferred_netagent_types[i].netagent_type) == 0) {
39037602
A
4299 break;
4300 }
4301
d9a64523
A
4302 if (necp_ifnet_matches_agent_type(ifp, parsed_parameters->preferred_netagent_types[i].netagent_domain, parsed_parameters->preferred_netagent_types[i].netagent_type, TRUE)) {
4303 (*preferred_count)++;
cb323159
A
4304 if (require_scoped_field) {
4305 matched_some_scoped_field = TRUE;
4306 }
d9a64523
A
4307 }
4308 }
4309 }
4310
4311 if (parsed_parameters->valid_fields & NECP_PARSED_PARAMETERS_FIELD_AVOIDED_AGENT) {
cb323159 4312 for (int i = 0; i < NECP_MAX_AGENT_PARAMETERS; i++) {
d9a64523
A
4313 if (uuid_is_null(parsed_parameters->avoided_netagents[i])) {
4314 break;
4315 }
4316
4317 if (!necp_ifnet_matches_agent(ifp, &parsed_parameters->avoided_netagents[i], TRUE)) {
4318 (*preferred_count)++;
4319 }
4320 }
4321 }
4322
4323 if (parsed_parameters->valid_fields & NECP_PARSED_PARAMETERS_FIELD_AVOIDED_AGENT_TYPE) {
cb323159 4324 for (int i = 0; i < NECP_MAX_AGENT_PARAMETERS; i++) {
d9a64523 4325 if (strlen(parsed_parameters->avoided_netagent_types[i].netagent_domain) == 0 &&
0a7de745 4326 strlen(parsed_parameters->avoided_netagent_types[i].netagent_type) == 0) {
d9a64523
A
4327 break;
4328 }
4329
4330 if (!necp_ifnet_matches_agent_type(ifp, parsed_parameters->avoided_netagent_types[i].netagent_domain,
0a7de745 4331 parsed_parameters->avoided_netagent_types[i].netagent_type, TRUE)) {
39037602
A
4332 (*preferred_count)++;
4333 }
4334 }
4335 }
4336 }
4337
cb323159
A
4338 if (require_scoped_field) {
4339 return matched_some_scoped_field;
4340 }
4341
0a7de745 4342 return TRUE;
39037602
A
4343}
4344
4345static bool
d9a64523 4346necp_find_matching_interface_index(struct necp_client_parsed_parameters *parsed_parameters,
0a7de745 4347 u_int *return_ifindex, bool *validate_agents)
39037602
A
4348{
4349 struct ifnet *ifp = NULL;
4350 u_int32_t best_preferred_count = 0;
4351 bool has_preferred_fields = FALSE;
4352 *return_ifindex = 0;
4353
4354 if (parsed_parameters->required_interface_index != 0) {
4355 *return_ifindex = parsed_parameters->required_interface_index;
0a7de745 4356 return TRUE;
39037602
A
4357 }
4358
cb323159
A
4359 // Check and save off flags
4360 u_int32_t flags = 0;
4361 bool has_prohibit_flags = FALSE;
4362 if (parsed_parameters->valid_fields & NECP_PARSED_PARAMETERS_FIELD_FLAGS) {
4363 flags = parsed_parameters->flags;
4364 has_prohibit_flags = (parsed_parameters->flags &
4365 (NECP_CLIENT_PARAMETER_FLAG_PROHIBIT_EXPENSIVE |
4366 NECP_CLIENT_PARAMETER_FLAG_PROHIBIT_CONSTRAINED));
4367 }
4368
4369 if (!(parsed_parameters->valid_fields & NECP_PARSED_PARAMETERS_INTERESTING_IFNET_FIELDS) &&
4370 !has_prohibit_flags) {
0a7de745 4371 return TRUE;
39037602
A
4372 }
4373
d9a64523 4374 has_preferred_fields = (parsed_parameters->valid_fields & NECP_PARSED_PARAMETERS_PREFERRED_FIELDS);
39037602
A
4375
4376 // We have interesting parameters to parse and find a matching interface
4377 ifnet_head_lock_shared();
4378
cb323159
A
4379 if (!(parsed_parameters->valid_fields & NECP_PARSED_PARAMETERS_SCOPED_FIELDS) &&
4380 !has_preferred_fields) {
39037602 4381 // We do have fields to match, but they are only prohibitory
5ba3f43e 4382 // If the first interface in the list matches, or there are no ordered interfaces, we don't need to scope
39037602 4383 ifp = TAILQ_FIRST(&ifnet_ordered_head);
cb323159 4384 if (ifp == NULL || necp_ifnet_matches_parameters(ifp, parsed_parameters, 0, NULL, false, false)) {
39037602
A
4385 // Don't set return_ifindex, so the client doesn't need to scope
4386 ifnet_head_done();
0a7de745 4387 return TRUE;
39037602
A
4388 }
4389 }
4390
4391 // First check the ordered interface list
4392 TAILQ_FOREACH(ifp, &ifnet_ordered_head, if_ordered_link) {
4393 u_int32_t preferred_count = 0;
cb323159 4394 if (necp_ifnet_matches_parameters(ifp, parsed_parameters, flags, &preferred_count, false, false)) {
39037602 4395 if (preferred_count > best_preferred_count ||
0a7de745 4396 *return_ifindex == 0) {
39037602
A
4397 // Everything matched, and is most preferred. Return this interface.
4398 *return_ifindex = ifp->if_index;
4399 best_preferred_count = preferred_count;
4400
4401 if (!has_preferred_fields) {
4402 break;
4403 }
4404 }
4405 }
cb323159
A
4406
4407 if (has_prohibit_flags &&
4408 ifp == TAILQ_FIRST(&ifnet_ordered_head)) {
4409 // This was the first interface. From here on, if the
4410 // client prohibited either expensive or constrained,
4411 // don't allow either as a secondary interface option.
4412 flags |= (NECP_CLIENT_PARAMETER_FLAG_PROHIBIT_EXPENSIVE |
4413 NECP_CLIENT_PARAMETER_FLAG_PROHIBIT_CONSTRAINED);
4414 }
39037602
A
4415 }
4416
cb323159
A
4417 bool is_listener = ((parsed_parameters->valid_fields & NECP_PARSED_PARAMETERS_FIELD_FLAGS) &&
4418 (parsed_parameters->flags & NECP_CLIENT_PARAMETER_FLAG_LISTENER));
4419
39037602 4420 // Then check the remaining interfaces
d9a64523 4421 if ((parsed_parameters->valid_fields & NECP_PARSED_PARAMETERS_SCOPED_FIELDS) &&
0a7de745 4422 ((!(parsed_parameters->valid_fields & NECP_PARSED_PARAMETERS_FIELD_REQUIRED_IFTYPE)) ||
cb323159
A
4423 !necp_interface_type_is_primary_eligible(parsed_parameters->required_interface_type) ||
4424 (parsed_parameters->valid_fields & NECP_PARSED_PARAMETERS_FIELD_LOCAL_ADDR) ||
4425 is_listener) &&
4426 (*return_ifindex == 0 || has_preferred_fields)) {
39037602
A
4427 TAILQ_FOREACH(ifp, &ifnet_head, if_link) {
4428 u_int32_t preferred_count = 0;
5ba3f43e 4429 if (NECP_IFP_IS_ON_ORDERED_LIST(ifp)) {
39037602
A
4430 // This interface was in the ordered list, skip
4431 continue;
4432 }
cb323159 4433 if (necp_ifnet_matches_parameters(ifp, parsed_parameters, flags, &preferred_count, false, true)) {
39037602 4434 if (preferred_count > best_preferred_count ||
0a7de745 4435 *return_ifindex == 0) {
39037602
A
4436 // Everything matched, and is most preferred. Return this interface.
4437 *return_ifindex = ifp->if_index;
4438 best_preferred_count = preferred_count;
4439
4440 if (!has_preferred_fields) {
4441 break;
4442 }
4443 }
4444 }
4445 }
4446 }
4447
4448 ifnet_head_done();
4449
d9a64523 4450 if ((parsed_parameters->valid_fields == (parsed_parameters->valid_fields & NECP_PARSED_PARAMETERS_PREFERRED_FIELDS)) &&
0a7de745 4451 best_preferred_count == 0) {
39037602
A
4452 // If only has preferred fields, and nothing was found, clear the interface index and return TRUE
4453 *return_ifindex = 0;
0a7de745 4454 return TRUE;
39037602
A
4455 }
4456
d9a64523 4457 if (*return_ifindex == 0 &&
0a7de745 4458 !(parsed_parameters->valid_fields & NECP_PARSED_PARAMETERS_SCOPED_IFNET_FIELDS)) {
d9a64523
A
4459 // Has required fields, but not including specific interface fields. Pass for now, and check
4460 // to see if agents are satisfied by policy.
4461 *validate_agents = TRUE;
0a7de745 4462 return TRUE;
d9a64523
A
4463 }
4464
0a7de745 4465 return *return_ifindex != 0;
39037602
A
4466}
4467
39037602
A
4468
4469static int
4470necp_skywalk_priv_check_cred(proc_t p, kauth_cred_t cred)
4471{
4472#pragma unused(p, cred)
0a7de745 4473 return 0;
39037602
A
4474}
4475
4476/// System calls
4477
4478int
4479necp_open(struct proc *p, struct necp_open_args *uap, int *retval)
4480{
4481#pragma unused(retval)
4482 int error = 0;
4483 struct necp_fd_data *fd_data = NULL;
4484 struct fileproc *fp = NULL;
4485 int fd = -1;
4486
d9a64523 4487 if (uap->flags & NECP_OPEN_FLAG_OBSERVER ||
0a7de745 4488 uap->flags & NECP_OPEN_FLAG_PUSH_OBSERVER) {
39037602 4489 if (necp_skywalk_priv_check_cred(p, kauth_cred_get()) != 0 &&
0a7de745 4490 priv_check_cred(kauth_cred_get(), PRIV_NET_PRIVILEGED_NETWORK_STATISTICS, 0) != 0) {
39037602
A
4491 NECPLOG0(LOG_ERR, "Client does not hold necessary entitlement to observe other NECP clients");
4492 error = EACCES;
4493 goto done;
4494 }
4495 }
4496
4497 error = falloc(p, &fp, &fd, vfs_context_current());
4498 if (error != 0) {
4499 goto done;
4500 }
4501
5ba3f43e 4502 if ((fd_data = zalloc(necp_client_fd_zone)) == NULL) {
39037602
A
4503 error = ENOMEM;
4504 goto done;
4505 }
4506
5ba3f43e
A
4507 memset(fd_data, 0, sizeof(*fd_data));
4508
4509 fd_data->necp_fd_type = necp_fd_type_client;
39037602 4510 fd_data->flags = uap->flags;
5ba3f43e 4511 RB_INIT(&fd_data->clients);
d9a64523 4512 RB_INIT(&fd_data->flows);
5ba3f43e 4513 TAILQ_INIT(&fd_data->update_list);
39037602
A
4514 lck_mtx_init(&fd_data->fd_lock, necp_fd_mtx_grp, necp_fd_mtx_attr);
4515 klist_init(&fd_data->si.si_note);
4516 fd_data->proc_pid = proc_pid(p);
4517
4518 fp->f_fglob->fg_flag = FREAD;
4519 fp->f_fglob->fg_ops = &necp_fd_ops;
4520 fp->f_fglob->fg_data = fd_data;
4521
4522 proc_fdlock(p);
4523
4524 *fdflags(p, fd) |= (UF_EXCLOSE | UF_FORKCLOSE);
4525 procfdtbl_releasefd(p, fd, NULL);
4526 fp_drop(p, fd, fp, 1);
39037602
A
4527
4528 *retval = fd;
4529
5ba3f43e
A
4530 if (fd_data->flags & NECP_OPEN_FLAG_PUSH_OBSERVER) {
4531 NECP_OBSERVER_LIST_LOCK_EXCLUSIVE();
4532 LIST_INSERT_HEAD(&necp_fd_observer_list, fd_data, chain);
4533 OSIncrementAtomic(&necp_observer_fd_count);
4534 NECP_OBSERVER_LIST_UNLOCK();
4535
4536 // Walk all existing clients and add them
4537 NECP_CLIENT_TREE_LOCK_SHARED();
4538 struct necp_client *existing_client = NULL;
4539 RB_FOREACH(existing_client, _necp_client_global_tree, &necp_client_global_tree) {
4540 NECP_CLIENT_LOCK(existing_client);
4541 necp_client_update_observer_add_internal(fd_data, existing_client);
4542 necp_client_update_observer_update_internal(fd_data, existing_client);
4543 NECP_CLIENT_UNLOCK(existing_client);
4544 }
4545 NECP_CLIENT_TREE_UNLOCK();
4546 } else {
4547 NECP_FD_LIST_LOCK_EXCLUSIVE();
4548 LIST_INSERT_HEAD(&necp_fd_list, fd_data, chain);
4549 OSIncrementAtomic(&necp_client_fd_count);
4550 NECP_FD_LIST_UNLOCK();
4551 }
39037602 4552
813fb2f6
A
4553 proc_fdunlock(p);
4554
39037602
A
4555done:
4556 if (error != 0) {
4557 if (fp != NULL) {
4558 fp_free(p, fd, fp);
4559 fp = NULL;
4560 }
4561 if (fd_data != NULL) {
5ba3f43e 4562 zfree(necp_client_fd_zone, fd_data);
39037602
A
4563 fd_data = NULL;
4564 }
4565 }
4566
0a7de745 4567 return error;
39037602
A
4568}
4569
cb323159
A
4570// All functions called directly from necp_client_action() to handle one of the
4571// types should be marked with NECP_CLIENT_ACTION_FUNCTION. This ensures that
4572// necp_client_action() does not inline all the actions into a single function.
4573#define NECP_CLIENT_ACTION_FUNCTION __attribute__((noinline))
4574
4575static NECP_CLIENT_ACTION_FUNCTION int
5ba3f43e 4576necp_client_add(struct proc *p, struct necp_fd_data *fd_data, struct necp_client_action_args *uap, int *retval)
39037602
A
4577{
4578 int error = 0;
4579 struct necp_client *client = NULL;
4580
5ba3f43e
A
4581 if (fd_data->flags & NECP_OPEN_FLAG_PUSH_OBSERVER) {
4582 NECPLOG0(LOG_ERR, "NECP client observers with push enabled may not add their own clients");
0a7de745 4583 return EINVAL;
5ba3f43e
A
4584 }
4585
39037602 4586 if (uap->client_id == 0 || uap->client_id_len != sizeof(uuid_t) ||
0a7de745
A
4587 uap->buffer_size == 0 || uap->buffer_size > NECP_MAX_CLIENT_PARAMETERS_SIZE || uap->buffer == 0) {
4588 return EINVAL;
39037602
A
4589 }
4590
4591 if ((client = _MALLOC(sizeof(struct necp_client) + uap->buffer_size, M_NECP,
0a7de745 4592 M_WAITOK | M_ZERO)) == NULL) {
39037602
A
4593 error = ENOMEM;
4594 goto done;
4595 }
4596
4597 error = copyin(uap->buffer, client->parameters, uap->buffer_size);
4598 if (error) {
4599 NECPLOG(LOG_ERR, "necp_client_add parameters copyin error (%d)", error);
4600 goto done;
4601 }
4602
5ba3f43e
A
4603 lck_mtx_init(&client->lock, necp_fd_mtx_grp, necp_fd_mtx_attr);
4604 lck_mtx_init(&client->route_lock, necp_fd_mtx_grp, necp_fd_mtx_attr);
cb323159
A
4605
4606 os_ref_init(&client->reference_count, &necp_client_refgrp); // Hold our reference until close
5ba3f43e 4607
39037602 4608 client->parameters_length = uap->buffer_size;
5ba3f43e 4609 client->proc_pid = fd_data->proc_pid; // Save off proc pid in case the client will persist past fd
d9a64523 4610 client->agent_handle = (void *)fd_data;
5ba3f43e 4611 client->platform_binary = ((csproc_get_platform_binary(p) == 0) ? 0 : 1);
39037602 4612
d9a64523 4613 necp_generate_client_id(client->client_id, false);
39037602 4614 LIST_INIT(&client->assertion_list);
d9a64523 4615 RB_INIT(&client->flow_registrations);
39037602
A
4616
4617 error = copyout(client->client_id, uap->client_id, sizeof(uuid_t));
4618 if (error) {
4619 NECPLOG(LOG_ERR, "necp_client_add client_id copyout error (%d)", error);
4620 goto done;
4621 }
4622
cb323159 4623
5ba3f43e
A
4624 necp_client_update_observer_add(client);
4625
4626 NECP_FD_LOCK(fd_data);
4627 RB_INSERT(_necp_client_tree, &fd_data->clients, client);
4628 OSIncrementAtomic(&necp_client_count);
4629 NECP_CLIENT_TREE_LOCK_EXCLUSIVE();
4630 RB_INSERT(_necp_client_global_tree, &necp_client_global_tree, client);
4631 NECP_CLIENT_TREE_UNLOCK();
39037602
A
4632
4633 // Prime the client result
5ba3f43e
A
4634 NECP_CLIENT_LOCK(client);
4635 (void)necp_update_client_result(current_proc(), fd_data, client, NULL);
4636 NECP_CLIENT_UNLOCK(client);
4637 NECP_FD_UNLOCK(fd_data);
39037602
A
4638done:
4639 if (error != 0) {
4640 if (client != NULL) {
4641 FREE(client, M_NECP);
4642 client = NULL;
4643 }
4644 }
4645 *retval = error;
4646
0a7de745 4647 return error;
39037602
A
4648}
4649
cb323159
A
4650static NECP_CLIENT_ACTION_FUNCTION int
4651necp_client_claim(struct proc *p, struct necp_fd_data *fd_data, struct necp_client_action_args *uap, int *retval)
4652{
4653 int error = 0;
4654 uuid_t client_id = {};
4655 struct necp_client *client = NULL;
4656
4657 if (uap->client_id == 0 || uap->client_id_len != sizeof(uuid_t)) {
4658 error = EINVAL;
4659 goto done;
4660 }
4661
4662 error = copyin(uap->client_id, client_id, sizeof(uuid_t));
4663 if (error) {
4664 NECPLOG(LOG_ERR, "necp_client_claim copyin client_id error (%d)", error);
4665 goto done;
4666 }
4667
4668 u_int64_t upid = proc_uniqueid(p);
4669
4670 NECP_FD_LIST_LOCK_SHARED();
4671
4672 struct necp_fd_data *find_fd = NULL;
4673 LIST_FOREACH(find_fd, &necp_fd_list, chain) {
4674 NECP_FD_LOCK(find_fd);
4675 struct necp_client *find_client = necp_client_fd_find_client_and_lock(find_fd, client_id);
4676 if (find_client != NULL) {
4677 if (find_client->delegated_upid == upid) {
4678 // Matched the client to claim; remove from the old fd
4679 client = find_client;
4680 RB_REMOVE(_necp_client_tree, &find_fd->clients, client);
4681 necp_client_retain_locked(client);
4682 }
4683 NECP_CLIENT_UNLOCK(find_client);
4684 }
4685 NECP_FD_UNLOCK(find_fd);
4686
4687 if (client != NULL) {
4688 break;
4689 }
4690 }
4691
4692 NECP_FD_LIST_UNLOCK();
4693
4694 if (client == NULL) {
4695 error = ENOENT;
4696 goto done;
4697 }
4698
4699 client->proc_pid = fd_data->proc_pid; // Transfer client to claiming pid
4700
4701 // Add matched client to our fd and re-run result
4702 NECP_FD_LOCK(fd_data);
4703 RB_INSERT(_necp_client_tree, &fd_data->clients, client);
4704 NECP_CLIENT_LOCK(client);
4705 (void)necp_update_client_result(current_proc(), fd_data, client, NULL);
4706 NECP_CLIENT_UNLOCK(client);
4707 NECP_FD_UNLOCK(fd_data);
4708
4709 necp_client_release(client);
4710
4711done:
4712 *retval = error;
4713
4714 return error;
4715}
4716
4717static NECP_CLIENT_ACTION_FUNCTION int
39037602
A
4718necp_client_remove(struct necp_fd_data *fd_data, struct necp_client_action_args *uap, int *retval)
4719{
4720 int error = 0;
5ba3f43e
A
4721 uuid_t client_id = {};
4722 struct ifnet_stats_per_flow flow_ifnet_stats = {};
39037602
A
4723
4724 if (uap->client_id == 0 || uap->client_id_len != sizeof(uuid_t)) {
4725 error = EINVAL;
4726 goto done;
4727 }
4728
4729 error = copyin(uap->client_id, client_id, sizeof(uuid_t));
4730 if (error) {
4731 NECPLOG(LOG_ERR, "necp_client_remove copyin client_id error (%d)", error);
4732 goto done;
4733 }
4734
5ba3f43e
A
4735 if (uap->buffer != 0 && uap->buffer_size == sizeof(flow_ifnet_stats)) {
4736 error = copyin(uap->buffer, &flow_ifnet_stats, uap->buffer_size);
4737 if (error) {
4738 NECPLOG(LOG_ERR, "necp_client_remove flow_ifnet_stats copyin error (%d)", error);
a39ff7e2 4739 // Not fatal; make sure to zero-out stats in case of partial copy
0a7de745 4740 memset(&flow_ifnet_stats, 0, sizeof(flow_ifnet_stats));
a39ff7e2 4741 error = 0;
5ba3f43e
A
4742 }
4743 } else if (uap->buffer != 0) {
4744 NECPLOG(LOG_ERR, "necp_client_remove unexpected parameters length (%zu)", uap->buffer_size);
4745 }
4746
5ba3f43e 4747 NECP_FD_LOCK(fd_data);
a39ff7e2 4748
5ba3f43e 4749 pid_t pid = fd_data->proc_pid;
d9a64523 4750 struct necp_client *client = necp_client_fd_find_client_unlocked(fd_data, client_id);
a39ff7e2 4751 if (client != NULL) {
d9a64523
A
4752 // Remove any flow registrations that match
4753 struct necp_client_flow_registration *flow_registration = NULL;
4754 struct necp_client_flow_registration *temp_flow_registration = NULL;
4755 RB_FOREACH_SAFE(flow_registration, _necp_fd_flow_tree, &fd_data->flows, temp_flow_registration) {
4756 if (flow_registration->client == client) {
4757 NECP_FLOW_TREE_LOCK_EXCLUSIVE();
4758 RB_REMOVE(_necp_client_flow_global_tree, &necp_client_flow_global_tree, flow_registration);
4759 NECP_FLOW_TREE_UNLOCK();
4760 RB_REMOVE(_necp_fd_flow_tree, &fd_data->flows, flow_registration);
4761 }
4762 }
4763 // Remove client from lists
a39ff7e2
A
4764 NECP_CLIENT_TREE_LOCK_EXCLUSIVE();
4765 RB_REMOVE(_necp_client_global_tree, &necp_client_global_tree, client);
4766 NECP_CLIENT_TREE_UNLOCK();
4767 RB_REMOVE(_necp_client_tree, &fd_data->clients, client);
39037602 4768 }
5ba3f43e 4769
d9a64523 4770
5ba3f43e
A
4771 NECP_FD_UNLOCK(fd_data);
4772
a39ff7e2
A
4773 if (client != NULL) {
4774 ASSERT(error == 0);
5ba3f43e 4775 necp_destroy_client(client, pid, true);
a39ff7e2
A
4776 } else {
4777 error = ENOENT;
4778 NECPLOG(LOG_ERR, "necp_client_remove invalid client_id (%d)", error);
5ba3f43e 4779 }
39037602
A
4780done:
4781 *retval = error;
4782
0a7de745 4783 return error;
39037602
A
4784}
4785
d9a64523 4786
cb323159
A
4787// Don't inline the function since it includes necp_client_parsed_parameters on the stack
4788static __attribute__((noinline)) int
5ba3f43e
A
4789necp_client_check_tcp_heuristics(struct necp_client *client, struct necp_client_flow *flow, u_int32_t *flags, u_int8_t *tfo_cookie, u_int8_t *tfo_cookie_len)
4790{
4791 struct necp_client_parsed_parameters parsed_parameters;
4792 int error = 0;
4793
4794 error = necp_client_parse_parameters(client->parameters,
0a7de745
A
4795 (u_int32_t)client->parameters_length,
4796 &parsed_parameters);
5ba3f43e
A
4797 if (error) {
4798 NECPLOG(LOG_ERR, "necp_client_parse_parameters error (%d)", error);
0a7de745 4799 return error;
5ba3f43e
A
4800 }
4801
4802 if ((flow->remote_addr.sa.sa_family != AF_INET &&
0a7de745
A
4803 flow->remote_addr.sa.sa_family != AF_INET6) ||
4804 (flow->local_addr.sa.sa_family != AF_INET &&
4805 flow->local_addr.sa.sa_family != AF_INET6)) {
4806 return EINVAL;
5ba3f43e
A
4807 }
4808
4809 NECP_CLIENT_ROUTE_LOCK(client);
4810
4811 if (client->current_route == NULL) {
0a7de745
A
4812 error = ENOENT;
4813 goto do_unlock;
5ba3f43e
A
4814 }
4815
4816 bool check_ecn = false;
4817 do {
4818 if ((parsed_parameters.flags & NECP_CLIENT_PARAMETER_FLAG_ECN_ENABLE) ==
0a7de745 4819 NECP_CLIENT_PARAMETER_FLAG_ECN_ENABLE) {
5ba3f43e
A
4820 check_ecn = true;
4821 break;
4822 }
4823
4824 if ((parsed_parameters.flags & NECP_CLIENT_PARAMETER_FLAG_ECN_DISABLE) ==
0a7de745 4825 NECP_CLIENT_PARAMETER_FLAG_ECN_DISABLE) {
5ba3f43e
A
4826 break;
4827 }
4828
4829 if (client->current_route != NULL) {
4830 if (client->current_route->rt_ifp->if_eflags & IFEF_ECN_ENABLE) {
4831 check_ecn = true;
4832 break;
4833 }
4834 if (client->current_route->rt_ifp->if_eflags & IFEF_ECN_DISABLE) {
4835 break;
4836 }
4837 }
4838
4839 bool inbound = ((parsed_parameters.flags & NECP_CLIENT_PARAMETER_FLAG_LISTENER) == 0);
4840 if ((inbound && tcp_ecn_inbound == 1) ||
0a7de745 4841 (!inbound && tcp_ecn_outbound == 1)) {
5ba3f43e
A
4842 check_ecn = true;
4843 }
4844 } while (false);
4845
4846 if (check_ecn) {
4847 if (tcp_heuristic_do_ecn_with_address(client->current_route->rt_ifp,
0a7de745 4848 (union sockaddr_in_4_6 *)&flow->local_addr)) {
5ba3f43e
A
4849 *flags |= NECP_CLIENT_RESULT_FLAG_ECN_ENABLED;
4850 }
4851 }
4852
4853 if ((parsed_parameters.flags & NECP_CLIENT_PARAMETER_FLAG_TFO_ENABLE) ==
0a7de745 4854 NECP_CLIENT_PARAMETER_FLAG_TFO_ENABLE) {
5ba3f43e 4855 if (!tcp_heuristic_do_tfo_with_address(client->current_route->rt_ifp,
0a7de745
A
4856 (union sockaddr_in_4_6 *)&flow->local_addr,
4857 (union sockaddr_in_4_6 *)&flow->remote_addr,
4858 tfo_cookie, tfo_cookie_len)) {
5ba3f43e
A
4859 *flags |= NECP_CLIENT_RESULT_FLAG_FAST_OPEN_BLOCKED;
4860 *tfo_cookie_len = 0;
4861 }
4862 } else {
4863 *flags |= NECP_CLIENT_RESULT_FLAG_FAST_OPEN_BLOCKED;
4864 *tfo_cookie_len = 0;
4865 }
4866do_unlock:
4867 NECP_CLIENT_ROUTE_UNLOCK(client);
4868
0a7de745 4869 return error;
5ba3f43e
A
4870}
4871
d9a64523
A
4872static size_t
4873necp_client_calculate_flow_tlv_size(struct necp_client_flow_registration *flow_registration)
4874{
4875 size_t assigned_results_size = 0;
4876 struct necp_client_flow *flow = NULL;
4877 LIST_FOREACH(flow, &flow_registration->flow_list, flow_chain) {
4878 if (flow->assigned) {
4879 size_t header_length = 0;
4880 if (flow->nexus) {
4881 header_length = sizeof(struct necp_client_nexus_flow_header);
4882 } else {
4883 header_length = sizeof(struct necp_client_flow_header);
4884 }
4885 assigned_results_size += (header_length + flow->assigned_results_length);
4886
4887 if (flow->has_protoctl_event) {
4888 assigned_results_size += sizeof(struct necp_client_flow_protoctl_event_header);
4889 }
4890 }
4891 }
4892 return assigned_results_size;
4893}
4894
4895static int
4896necp_client_fillout_flow_tlvs(struct necp_client *client,
0a7de745
A
4897 bool client_is_observed,
4898 struct necp_client_flow_registration *flow_registration,
4899 struct necp_client_action_args *uap,
4900 size_t *assigned_results_cursor)
d9a64523
A
4901{
4902 int error = 0;
4903 struct necp_client_flow *flow = NULL;
4904 LIST_FOREACH(flow, &flow_registration->flow_list, flow_chain) {
4905 if (flow->assigned) {
4906 // Write TLV headers
4907 struct necp_client_nexus_flow_header header = {};
4908 u_int32_t length = 0;
4909 u_int32_t flags = 0;
4910 u_int8_t tfo_cookie_len = 0;
4911 u_int8_t type = 0;
4912
4913 type = NECP_CLIENT_RESULT_FLOW_ID;
4914 length = sizeof(header.flow_header.flow_id);
4915 memcpy(&header.flow_header.flow_id_tlv_header.type, &type, sizeof(type));
4916 memcpy(&header.flow_header.flow_id_tlv_header.length, &length, sizeof(length));
4917 uuid_copy(header.flow_header.flow_id, flow_registration->registration_id);
4918
4919 if (flow->nexus) {
4920 if (flow->check_tcp_heuristics) {
4921 u_int8_t tfo_cookie[NECP_TFO_COOKIE_LEN_MAX];
4922 tfo_cookie_len = NECP_TFO_COOKIE_LEN_MAX;
4923
4924 if (necp_client_check_tcp_heuristics(client, flow, &flags,
0a7de745 4925 tfo_cookie, &tfo_cookie_len) != 0) {
d9a64523
A
4926 tfo_cookie_len = 0;
4927 } else {
4928 flow->check_tcp_heuristics = FALSE;
4929
4930 if (tfo_cookie_len != 0) {
4931 type = NECP_CLIENT_RESULT_TFO_COOKIE;
4932 length = tfo_cookie_len;
4933 memcpy(&header.tfo_cookie_tlv_header.type, &type, sizeof(type));
4934 memcpy(&header.tfo_cookie_tlv_header.length, &length, sizeof(length));
4935 memcpy(&header.tfo_cookie_value, tfo_cookie, tfo_cookie_len);
4936 }
4937 }
4938 }
4939 }
4940
4941 size_t header_length = 0;
4942 if (flow->nexus) {
4943 if (tfo_cookie_len != 0) {
4944 header_length = sizeof(struct necp_client_nexus_flow_header) - (NECP_TFO_COOKIE_LEN_MAX - tfo_cookie_len);
4945 } else {
4946 header_length = sizeof(struct necp_client_nexus_flow_header) - sizeof(struct necp_tlv_header) - NECP_TFO_COOKIE_LEN_MAX;
4947 }
4948 } else {
4949 header_length = sizeof(struct necp_client_flow_header);
4950 }
4951
4952 type = NECP_CLIENT_RESULT_FLAGS;
4953 length = sizeof(header.flow_header.flags_value);
4954 memcpy(&header.flow_header.flags_tlv_header.type, &type, sizeof(type));
4955 memcpy(&header.flow_header.flags_tlv_header.length, &length, sizeof(length));
4956 if (flow->assigned) {
4957 flags |= NECP_CLIENT_RESULT_FLAG_FLOW_ASSIGNED;
4958 }
4959 if (flow->viable) {
4960 flags |= NECP_CLIENT_RESULT_FLAG_FLOW_VIABLE;
4961 }
4962 if (flow_registration->defunct) {
4963 flags |= NECP_CLIENT_RESULT_FLAG_DEFUNCT;
4964 }
4965 flags |= flow->necp_flow_flags;
4966 memcpy(&header.flow_header.flags_value, &flags, sizeof(flags));
4967
4968 type = NECP_CLIENT_RESULT_INTERFACE;
4969 length = sizeof(header.flow_header.interface_value);
4970 memcpy(&header.flow_header.interface_tlv_header.type, &type, sizeof(type));
4971 memcpy(&header.flow_header.interface_tlv_header.length, &length, sizeof(length));
4972
4973 struct necp_client_result_interface interface_struct;
4974 interface_struct.generation = 0;
4975 interface_struct.index = flow->interface_index;
4976
4977 memcpy(&header.flow_header.interface_value, &interface_struct, sizeof(interface_struct));
4978 if (flow->nexus) {
4979 type = NECP_CLIENT_RESULT_NETAGENT;
4980 length = sizeof(header.agent_value);
4981 memcpy(&header.agent_tlv_header.type, &type, sizeof(type));
4982 memcpy(&header.agent_tlv_header.length, &length, sizeof(length));
4983
4984 struct necp_client_result_netagent agent_struct;
4985 agent_struct.generation = 0;
4986 uuid_copy(agent_struct.netagent_uuid, flow->u.nexus_agent);
4987
4988 memcpy(&header.agent_value, &agent_struct, sizeof(agent_struct));
4989 }
4990
4991 // Don't include outer TLV header in length field
4992 type = NECP_CLIENT_RESULT_FLOW;
4993 length = (header_length - sizeof(struct necp_tlv_header) + flow->assigned_results_length);
4994 if (flow->has_protoctl_event) {
4995 length += sizeof(struct necp_client_flow_protoctl_event_header);
4996 }
4997 memcpy(&header.flow_header.outer_header.type, &type, sizeof(type));
4998 memcpy(&header.flow_header.outer_header.length, &length, sizeof(length));
4999
5000 error = copyout(&header, uap->buffer + client->result_length + *assigned_results_cursor, header_length);
5001 if (error) {
5002 NECPLOG(LOG_ERR, "necp_client_copy assigned results tlv_header copyout error (%d)", error);
0a7de745 5003 return error;
d9a64523
A
5004 }
5005 *assigned_results_cursor += header_length;
5006
5007 if (flow->assigned_results && flow->assigned_results_length) {
5008 // Write inner TLVs
5009 error = copyout(flow->assigned_results, uap->buffer + client->result_length + *assigned_results_cursor,
0a7de745 5010 flow->assigned_results_length);
d9a64523
A
5011 if (error) {
5012 NECPLOG(LOG_ERR, "necp_client_copy assigned results copyout error (%d)", error);
0a7de745 5013 return error;
d9a64523
A
5014 }
5015 }
5016 *assigned_results_cursor += flow->assigned_results_length;
5017
5018 /* Read the protocol event and reset it */
5019 if (flow->has_protoctl_event) {
5020 struct necp_client_flow_protoctl_event_header protoctl_event_header = {};
5021
5022 type = NECP_CLIENT_RESULT_PROTO_CTL_EVENT;
5023 length = sizeof(protoctl_event_header.protoctl_event);
5024
5025 memcpy(&protoctl_event_header.protoctl_tlv_header.type, &type, sizeof(type));
5026 memcpy(&protoctl_event_header.protoctl_tlv_header.length, &length, sizeof(length));
5027 memcpy(&protoctl_event_header.protoctl_event, &flow->protoctl_event,
0a7de745 5028 sizeof(flow->protoctl_event));
d9a64523
A
5029
5030 error = copyout(&protoctl_event_header, uap->buffer + client->result_length + *assigned_results_cursor,
0a7de745 5031 sizeof(protoctl_event_header));
d9a64523
A
5032
5033 if (error) {
5034 NECPLOG(LOG_ERR, "necp_client_copy protocol control event results"
0a7de745
A
5035 " tlv_header copyout error (%d)", error);
5036 return error;
d9a64523
A
5037 }
5038 *assigned_results_cursor += sizeof(protoctl_event_header);
5039 flow->has_protoctl_event = FALSE;
5040 flow->protoctl_event.protoctl_event_code = 0;
5041 flow->protoctl_event.protoctl_event_val = 0;
5042 flow->protoctl_event.protoctl_event_tcp_seq_num = 0;
5043 }
5044 }
5045 }
5046 if (!client_is_observed) {
5047 flow_registration->flow_result_read = TRUE;
5048 }
0a7de745 5049 return 0;
d9a64523
A
5050}
5051
39037602 5052static int
d9a64523 5053necp_client_copy_internal(struct necp_client *client, uuid_t client_id, bool client_is_observed, struct necp_client_action_args *uap, int *retval)
39037602 5054{
d9a64523 5055 NECP_CLIENT_ASSERT_LOCKED(client);
39037602
A
5056 int error = 0;
5057 // Copy results out
5058 if (uap->action == NECP_CLIENT_ACTION_COPY_PARAMETERS) {
5059 if (uap->buffer_size < client->parameters_length) {
0a7de745 5060 return EINVAL;
39037602
A
5061 }
5062 error = copyout(client->parameters, uap->buffer, client->parameters_length);
5063 if (error) {
5064 NECPLOG(LOG_ERR, "necp_client_copy parameters copyout error (%d)", error);
0a7de745 5065 return error;
39037602
A
5066 }
5067 *retval = client->parameters_length;
5ba3f43e 5068 } else if (uap->action == NECP_CLIENT_ACTION_COPY_UPDATED_RESULT &&
0a7de745 5069 client->result_read && !necp_client_has_unread_flows(client)) {
5ba3f43e
A
5070 // Copy updates only, but nothing to read
5071 // Just return 0 for bytes read
5072 *retval = 0;
5073 } else if (uap->action == NECP_CLIENT_ACTION_COPY_RESULT ||
0a7de745 5074 uap->action == NECP_CLIENT_ACTION_COPY_UPDATED_RESULT) {
5ba3f43e 5075 size_t assigned_results_size = 0;
5ba3f43e 5076
d9a64523
A
5077 bool some_flow_is_defunct = false;
5078 struct necp_client_flow_registration *single_flow_registration = NULL;
5079 if (necp_client_id_is_flow(client_id)) {
5080 single_flow_registration = necp_client_find_flow(client, client_id);
5081 if (single_flow_registration != NULL) {
5082 assigned_results_size += necp_client_calculate_flow_tlv_size(single_flow_registration);
5083 }
5084 } else {
5085 // This request is for the client, so copy everything
5086 struct necp_client_flow_registration *flow_registration = NULL;
5087 RB_FOREACH(flow_registration, _necp_client_flow_tree, &client->flow_registrations) {
5088 if (flow_registration->defunct) {
5089 some_flow_is_defunct = true;
5ba3f43e 5090 }
d9a64523 5091 assigned_results_size += necp_client_calculate_flow_tlv_size(flow_registration);
5ba3f43e
A
5092 }
5093 }
5094 if (uap->buffer_size < (client->result_length + assigned_results_size)) {
0a7de745 5095 return EINVAL;
d9a64523
A
5096 }
5097
5098 u_int32_t original_flags = 0;
5099 bool flags_updated = false;
5100 if (some_flow_is_defunct && client->legacy_client_is_flow) {
5101 // If our client expects the defunct flag in the client, add it now
5102 u_int32_t client_flags = 0;
5103 u_int32_t value_size = 0;
5104 u_int8_t *flags_pointer = necp_buffer_get_tlv_value(client->result, 0, &value_size);
5105 if (flags_pointer != NULL && value_size == sizeof(client_flags)) {
5106 memcpy(&client_flags, flags_pointer, value_size);
5107 original_flags = client_flags;
5108 client_flags |= NECP_CLIENT_RESULT_FLAG_DEFUNCT;
5109 (void)necp_buffer_write_tlv_if_different(client->result, NECP_CLIENT_RESULT_FLAGS,
0a7de745
A
5110 sizeof(client_flags), &client_flags, &flags_updated,
5111 client->result, sizeof(client->result));
d9a64523 5112 }
39037602 5113 }
d9a64523 5114
39037602 5115 error = copyout(client->result, uap->buffer, client->result_length);
d9a64523
A
5116
5117 if (flags_updated) {
5118 // Revert stored flags
5119 (void)necp_buffer_write_tlv_if_different(client->result, NECP_CLIENT_RESULT_FLAGS,
0a7de745
A
5120 sizeof(original_flags), &original_flags, &flags_updated,
5121 client->result, sizeof(client->result));
d9a64523
A
5122 }
5123
39037602
A
5124 if (error) {
5125 NECPLOG(LOG_ERR, "necp_client_copy result copyout error (%d)", error);
0a7de745 5126 return error;
39037602 5127 }
5ba3f43e
A
5128
5129 size_t assigned_results_cursor = 0;
d9a64523
A
5130 if (necp_client_id_is_flow(client_id)) {
5131 if (single_flow_registration != NULL) {
5132 error = necp_client_fillout_flow_tlvs(client, client_is_observed, single_flow_registration, uap, &assigned_results_cursor);
5133 if (error != 0) {
0a7de745 5134 return error;
5ba3f43e 5135 }
d9a64523
A
5136 }
5137 } else {
5138 // This request is for the client, so copy everything
5139 struct necp_client_flow_registration *flow_registration = NULL;
5140 RB_FOREACH(flow_registration, _necp_client_flow_tree, &client->flow_registrations) {
5141 error = necp_client_fillout_flow_tlvs(client, client_is_observed, flow_registration, uap, &assigned_results_cursor);
5142 if (error != 0) {
0a7de745 5143 return error;
5ba3f43e 5144 }
39037602 5145 }
39037602
A
5146 }
5147
5ba3f43e
A
5148 *retval = client->result_length + assigned_results_cursor;
5149
39037602
A
5150 if (!client_is_observed) {
5151 client->result_read = TRUE;
39037602
A
5152 }
5153 }
5154
0a7de745 5155 return 0;
39037602
A
5156}
5157
cb323159 5158static NECP_CLIENT_ACTION_FUNCTION int
39037602
A
5159necp_client_copy(struct necp_fd_data *fd_data, struct necp_client_action_args *uap, int *retval)
5160{
5161 int error = 0;
39037602
A
5162 struct necp_client *client = NULL;
5163 uuid_t client_id;
5164 uuid_clear(client_id);
5165
5166 *retval = 0;
5167
5168 if (uap->buffer_size == 0 || uap->buffer == 0) {
0a7de745 5169 return EINVAL;
39037602
A
5170 }
5171
5172 if (uap->action != NECP_CLIENT_ACTION_COPY_PARAMETERS &&
0a7de745
A
5173 uap->action != NECP_CLIENT_ACTION_COPY_RESULT &&
5174 uap->action != NECP_CLIENT_ACTION_COPY_UPDATED_RESULT) {
5175 return EINVAL;
39037602
A
5176 }
5177
5178 if (uap->client_id) {
5179 if (uap->client_id_len != sizeof(uuid_t)) {
5180 NECPLOG(LOG_ERR, "Incorrect length (got %d, expected %d)", uap->client_id_len, sizeof(uuid_t));
0a7de745 5181 return ERANGE;
39037602
A
5182 }
5183
5184 error = copyin(uap->client_id, client_id, sizeof(uuid_t));
5185 if (error) {
5186 NECPLOG(LOG_ERR, "necp_client_copy client_id copyin error (%d)", error);
0a7de745 5187 return error;
39037602
A
5188 }
5189 }
5190
a39ff7e2
A
5191 const bool is_wildcard = (bool)uuid_is_null(client_id);
5192
5ba3f43e 5193 NECP_FD_LOCK(fd_data);
a39ff7e2
A
5194
5195 if (is_wildcard) {
5196 if (uap->action == NECP_CLIENT_ACTION_COPY_RESULT || uap->action == NECP_CLIENT_ACTION_COPY_UPDATED_RESULT) {
5197 struct necp_client *find_client = NULL;
5198 RB_FOREACH(find_client, _necp_client_tree, &fd_data->clients) {
5199 NECP_CLIENT_LOCK(find_client);
d9a64523 5200 if (!find_client->result_read || necp_client_has_unread_flows(find_client)) {
a39ff7e2
A
5201 client = find_client;
5202 // Leave the client locked, and break
5203 break;
5204 }
5205 NECP_CLIENT_UNLOCK(find_client);
39037602 5206 }
39037602 5207 }
a39ff7e2
A
5208 } else {
5209 client = necp_client_fd_find_client_and_lock(fd_data, client_id);
39037602
A
5210 }
5211
5212 if (client != NULL) {
a39ff7e2 5213 // If client is set, it is locked
d9a64523 5214 error = necp_client_copy_internal(client, client_id, FALSE, uap, retval);
a39ff7e2 5215 NECP_CLIENT_UNLOCK(client);
39037602
A
5216 }
5217
a39ff7e2 5218 // Unlock our own fd before moving on or returning
5ba3f43e 5219 NECP_FD_UNLOCK(fd_data);
39037602
A
5220
5221 if (client == NULL) {
5222 if (fd_data->flags & NECP_OPEN_FLAG_OBSERVER) {
5223 // Observers are allowed to lookup clients on other fds
5224
5ba3f43e
A
5225 // Lock tree
5226 NECP_CLIENT_TREE_LOCK_SHARED();
39037602 5227
5ba3f43e 5228 bool found_client = FALSE;
39037602 5229
d9a64523 5230 client = necp_find_client_and_lock(client_id);
5ba3f43e 5231 if (client != NULL) {
5ba3f43e
A
5232 // Matched, copy out data
5233 found_client = TRUE;
d9a64523 5234 error = necp_client_copy_internal(client, client_id, TRUE, uap, retval);
5ba3f43e 5235 NECP_CLIENT_UNLOCK(client);
39037602
A
5236 }
5237
5ba3f43e
A
5238 // Unlock tree
5239 NECP_CLIENT_TREE_UNLOCK();
39037602
A
5240
5241 // No client found, fail
5ba3f43e 5242 if (!found_client) {
0a7de745 5243 return ENOENT;
39037602
A
5244 }
5245 } else {
5246 // No client found, and not allowed to search other fds, fail
0a7de745 5247 return ENOENT;
39037602
A
5248 }
5249 }
5250
0a7de745 5251 return error;
39037602
A
5252}
5253
cb323159 5254static NECP_CLIENT_ACTION_FUNCTION int
5ba3f43e
A
5255necp_client_copy_client_update(struct necp_fd_data *fd_data, struct necp_client_action_args *uap, int *retval)
5256{
5257 int error = 0;
5258
5259 *retval = 0;
5260
5261 if (!(fd_data->flags & NECP_OPEN_FLAG_PUSH_OBSERVER)) {
5262 NECPLOG0(LOG_ERR, "NECP fd is not observer, cannot copy client update");
0a7de745 5263 return EINVAL;
5ba3f43e
A
5264 }
5265
5266 if (uap->client_id_len != sizeof(uuid_t) || uap->client_id == 0) {
5267 NECPLOG0(LOG_ERR, "Client id invalid, cannot copy client update");
0a7de745 5268 return EINVAL;
5ba3f43e
A
5269 }
5270
5271 if (uap->buffer_size == 0 || uap->buffer == 0) {
5272 NECPLOG0(LOG_ERR, "Buffer invalid, cannot copy client update");
0a7de745 5273 return EINVAL;
5ba3f43e
A
5274 }
5275
5276 NECP_FD_LOCK(fd_data);
5277 struct necp_client_update *client_update = TAILQ_FIRST(&fd_data->update_list);
5278 if (client_update != NULL) {
5279 TAILQ_REMOVE(&fd_data->update_list, client_update, chain);
5280 VERIFY(fd_data->update_count > 0);
5281 fd_data->update_count--;
5282 }
5283 NECP_FD_UNLOCK(fd_data);
5284
5285 if (client_update != NULL) {
5286 error = copyout(client_update->client_id, uap->client_id, sizeof(uuid_t));
5287 if (error) {
5288 NECPLOG(LOG_ERR, "Copy client update copyout client id error (%d)", error);
5289 } else {
5290 if (uap->buffer_size < client_update->update_length) {
5291 NECPLOG(LOG_ERR, "Buffer size cannot hold update (%zu < %zu)", uap->buffer_size, client_update->update_length);
5292 error = EINVAL;
5293 } else {
5294 error = copyout(&client_update->update, uap->buffer, client_update->update_length);
5295 if (error) {
5296 NECPLOG(LOG_ERR, "Copy client update copyout error (%d)", error);
5297 } else {
5298 *retval = client_update->update_length;
5299 }
5300 }
5301 }
5302
5303 FREE(client_update, M_NECP);
5304 client_update = NULL;
5305 } else {
5306 error = ENOENT;
5307 }
5308
0a7de745 5309 return error;
5ba3f43e
A
5310}
5311
5312static int
d9a64523 5313necp_client_copy_parameters_locked(struct necp_client *client,
0a7de745 5314 struct necp_client_nexus_parameters *parameters)
5ba3f43e
A
5315{
5316 VERIFY(parameters != NULL);
5317
5318 struct necp_client_parsed_parameters parsed_parameters = {};
5319 int error = necp_client_parse_parameters(client->parameters, (u_int32_t)client->parameters_length, &parsed_parameters);
5320
5321 parameters->pid = client->proc_pid;
5322 if (parsed_parameters.valid_fields & NECP_PARSED_PARAMETERS_FIELD_EFFECTIVE_PID) {
5323 parameters->epid = parsed_parameters.effective_pid;
5324 } else {
5325 parameters->epid = parameters->pid;
5326 }
5327 memcpy(&parameters->local_addr, &parsed_parameters.local_addr, sizeof(parameters->local_addr));
5328 memcpy(&parameters->remote_addr, &parsed_parameters.remote_addr, sizeof(parameters->remote_addr));
5329 parameters->ip_protocol = parsed_parameters.ip_protocol;
cb323159
A
5330 if (parsed_parameters.valid_fields & NECP_PARSED_PARAMETERS_FIELD_TRANSPORT_PROTOCOL) {
5331 parameters->transport_protocol = parsed_parameters.transport_protocol;
5332 } else {
5333 parameters->transport_protocol = parsed_parameters.ip_protocol;
5334 }
5335 parameters->ethertype = parsed_parameters.ethertype;
5ba3f43e 5336 parameters->traffic_class = parsed_parameters.traffic_class;
ea3f0419
A
5337 if (uuid_is_null(client->override_euuid)) {
5338 uuid_copy(parameters->euuid, parsed_parameters.effective_uuid);
5339 } else {
5340 uuid_copy(parameters->euuid, client->override_euuid);
5341 }
5ba3f43e 5342 parameters->is_listener = (parsed_parameters.flags & NECP_CLIENT_PARAMETER_FLAG_LISTENER) ? 1 : 0;
cb323159
A
5343 parameters->is_interpose = (parsed_parameters.flags & NECP_CLIENT_PARAMETER_FLAG_INTERPOSE) ? 1 : 0;
5344 parameters->is_custom_ether = (parsed_parameters.flags & NECP_CLIENT_PARAMETER_FLAG_CUSTOM_ETHER) ? 1 : 0;
5ba3f43e
A
5345 parameters->policy_id = client->policy_id;
5346
5347 // parse client result flag
5348 u_int32_t client_result_flags = 0;
5349 u_int32_t value_size = 0;
5350 u_int8_t *flags_pointer = NULL;
5351 flags_pointer = necp_buffer_get_tlv_value(client->result, 0, &value_size);
5352 if (flags_pointer && value_size == sizeof(client_result_flags)) {
5353 memcpy(&client_result_flags, flags_pointer, value_size);
5354 }
5355 parameters->allow_qos_marking = (client_result_flags & NECP_CLIENT_RESULT_FLAG_ALLOW_QOS_MARKING) ? 1 : 0;
5356
cb323159
A
5357 if (parsed_parameters.valid_fields & NECP_PARSED_PARAMETERS_FIELD_LOCAL_ADDR_PREFERENCE) {
5358 if (parsed_parameters.local_address_preference == NECP_CLIENT_PARAMETER_LOCAL_ADDRESS_PREFERENCE_DEFAULT) {
5359 parameters->override_address_selection = false;
5360 } else if (parsed_parameters.local_address_preference == NECP_CLIENT_PARAMETER_LOCAL_ADDRESS_PREFERENCE_TEMPORARY) {
5361 parameters->override_address_selection = true;
5362 parameters->use_stable_address = false;
5363 } else if (parsed_parameters.local_address_preference == NECP_CLIENT_PARAMETER_LOCAL_ADDRESS_PREFERENCE_STABLE) {
5364 parameters->override_address_selection = true;
5365 parameters->use_stable_address = true;
5366 }
5367 } else {
5368 parameters->override_address_selection = false;
5369 }
5370
0a7de745 5371 return error;
5ba3f43e
A
5372}
5373
cb323159 5374static NECP_CLIENT_ACTION_FUNCTION int
39037602
A
5375necp_client_list(struct necp_fd_data *fd_data, struct necp_client_action_args *uap, int *retval)
5376{
5377 int error = 0;
5378 struct necp_client *find_client = NULL;
5379 uuid_t *list = NULL;
5380 u_int32_t requested_client_count = 0;
5381 u_int32_t client_count = 0;
5ba3f43e 5382 size_t copy_buffer_size = 0;
39037602
A
5383
5384 if (uap->buffer_size < sizeof(requested_client_count) || uap->buffer == 0) {
5385 error = EINVAL;
5386 goto done;
5387 }
5388
5389 if (!(fd_data->flags & NECP_OPEN_FLAG_OBSERVER)) {
5390 NECPLOG0(LOG_ERR, "Client does not hold necessary entitlement to list other NECP clients");
5391 error = EACCES;
5392 goto done;
5393 }
5394
5395 error = copyin(uap->buffer, &requested_client_count, sizeof(requested_client_count));
5396 if (error) {
5397 goto done;
5398 }
5399
5ba3f43e
A
5400 if (os_mul_overflow(sizeof(uuid_t), requested_client_count, &copy_buffer_size)) {
5401 error = ERANGE;
5402 goto done;
5403 }
5404
5405 if (uap->buffer_size - sizeof(requested_client_count) != copy_buffer_size) {
5406 error = EINVAL;
5407 goto done;
5408 }
5409
5410 if (copy_buffer_size > NECP_MAX_CLIENT_LIST_SIZE) {
39037602
A
5411 error = EINVAL;
5412 goto done;
5413 }
5414
5415 if (requested_client_count > 0) {
5ba3f43e 5416 if ((list = _MALLOC(copy_buffer_size, M_NECP, M_WAITOK | M_ZERO)) == NULL) {
39037602
A
5417 error = ENOMEM;
5418 goto done;
5419 }
5420 }
5421
5ba3f43e
A
5422 // Lock tree
5423 NECP_CLIENT_TREE_LOCK_SHARED();
5424
5425 find_client = NULL;
5426 RB_FOREACH(find_client, _necp_client_global_tree, &necp_client_global_tree) {
5427 NECP_CLIENT_LOCK(find_client);
5428 if (!uuid_is_null(find_client->client_id)) {
5429 if (client_count < requested_client_count) {
5430 uuid_copy(list[client_count], find_client->client_id);
39037602 5431 }
5ba3f43e 5432 client_count++;
39037602 5433 }
5ba3f43e 5434 NECP_CLIENT_UNLOCK(find_client);
39037602
A
5435 }
5436
5ba3f43e
A
5437 // Unlock tree
5438 NECP_CLIENT_TREE_UNLOCK();
39037602
A
5439
5440 error = copyout(&client_count, uap->buffer, sizeof(client_count));
5441 if (error) {
5442 NECPLOG(LOG_ERR, "necp_client_list buffer copyout error (%d)", error);
5443 goto done;
5444 }
5445
5446 if (requested_client_count > 0 &&
0a7de745
A
5447 client_count > 0 &&
5448 list != NULL) {
5ba3f43e 5449 error = copyout(list, uap->buffer + sizeof(client_count), copy_buffer_size);
39037602
A
5450 if (error) {
5451 NECPLOG(LOG_ERR, "necp_client_list client count copyout error (%d)", error);
5452 goto done;
5453 }
5454 }
5455done:
5456 if (list != NULL) {
5457 FREE(list, M_NECP);
5458 }
5459 *retval = error;
39037602 5460
0a7de745 5461 return error;
39037602
A
5462}
5463
5ba3f43e 5464
39037602
A
5465static void
5466necp_client_add_assertion(struct necp_client *client, uuid_t netagent_uuid)
5467{
5468 struct necp_client_assertion *new_assertion = NULL;
5469
5470 MALLOC(new_assertion, struct necp_client_assertion *, sizeof(*new_assertion), M_NECP, M_WAITOK);
5471 if (new_assertion == NULL) {
5472 NECPLOG0(LOG_ERR, "Failed to allocate assertion");
5473 return;
5474 }
5475
5476 uuid_copy(new_assertion->asserted_netagent, netagent_uuid);
5477
5478 LIST_INSERT_HEAD(&client->assertion_list, new_assertion, assertion_chain);
5479}
5480
5481static bool
5482necp_client_remove_assertion(struct necp_client *client, uuid_t netagent_uuid)
5483{
5484 struct necp_client_assertion *found_assertion = NULL;
5485 struct necp_client_assertion *search_assertion = NULL;
5486 LIST_FOREACH(search_assertion, &client->assertion_list, assertion_chain) {
5487 if (uuid_compare(search_assertion->asserted_netagent, netagent_uuid) == 0) {
5488 found_assertion = search_assertion;
5489 break;
5490 }
5491 }
5492
5493 if (found_assertion == NULL) {
5494 NECPLOG0(LOG_ERR, "Netagent uuid not previously asserted");
5495 return false;
5496 }
5497
5498 LIST_REMOVE(found_assertion, assertion_chain);
5499 FREE(found_assertion, M_NECP);
5500 return true;
5501}
5502
cb323159 5503static NECP_CLIENT_ACTION_FUNCTION int
39037602
A
5504necp_client_agent_action(struct necp_fd_data *fd_data, struct necp_client_action_args *uap, int *retval)
5505{
5506 int error = 0;
39037602
A
5507 struct necp_client *client = NULL;
5508 uuid_t client_id;
5509 bool acted_on_agent = FALSE;
5510 u_int8_t *parameters = NULL;
5511 size_t parameters_size = uap->buffer_size;
5512
5513 if (uap->client_id == 0 || uap->client_id_len != sizeof(uuid_t) ||
0a7de745 5514 uap->buffer_size == 0 || uap->buffer == 0) {
a39ff7e2 5515 NECPLOG0(LOG_ERR, "necp_client_agent_action invalid parameters");
39037602
A
5516 error = EINVAL;
5517 goto done;
5518 }
5519
5520 error = copyin(uap->client_id, client_id, sizeof(uuid_t));
5521 if (error) {
5522 NECPLOG(LOG_ERR, "necp_client_agent_action copyin client_id error (%d)", error);
5523 goto done;
5524 }
5525
9d749ea3
A
5526 if (uap->buffer_size > NECP_MAX_AGENT_ACTION_SIZE) {
5527 NECPLOG(LOG_ERR, "necp_client_agent_action invalid buffer size (>%u)", NECP_MAX_AGENT_ACTION_SIZE);
5528 error = EINVAL;
5529 goto done;
5530 }
5531
39037602 5532 if ((parameters = _MALLOC(uap->buffer_size, M_NECP, M_WAITOK | M_ZERO)) == NULL) {
a39ff7e2 5533 NECPLOG0(LOG_ERR, "necp_client_agent_action malloc failed");
39037602
A
5534 error = ENOMEM;
5535 goto done;
5536 }
5537
5538 error = copyin(uap->buffer, parameters, uap->buffer_size);
5539 if (error) {
5540 NECPLOG(LOG_ERR, "necp_client_agent_action parameters copyin error (%d)", error);
5541 goto done;
5542 }
5543
5ba3f43e
A
5544 NECP_FD_LOCK(fd_data);
5545 client = necp_client_fd_find_client_and_lock(fd_data, client_id);
5546 if (client != NULL) {
39037602 5547 size_t offset = 0;
5ba3f43e 5548 while ((offset + sizeof(struct necp_tlv_header)) <= parameters_size) {
39037602
A
5549 u_int8_t type = necp_buffer_get_tlv_type(parameters, offset);
5550 u_int32_t length = necp_buffer_get_tlv_length(parameters, offset);
5551
5ba3f43e 5552 if (length > (parameters_size - (offset + sizeof(struct necp_tlv_header)))) {
813fb2f6
A
5553 // If the length is larger than what can fit in the remaining parameters size, bail
5554 NECPLOG(LOG_ERR, "Invalid TLV length (%u)", length);
5555 break;
5556 }
5557
5558 if (length > 0) {
39037602
A
5559 u_int8_t *value = necp_buffer_get_tlv_value(parameters, offset, NULL);
5560 if (length >= sizeof(uuid_t) &&
0a7de745
A
5561 value != NULL &&
5562 (type == NECP_CLIENT_PARAMETER_TRIGGER_AGENT ||
5563 type == NECP_CLIENT_PARAMETER_ASSERT_AGENT ||
5564 type == NECP_CLIENT_PARAMETER_UNASSERT_AGENT)) {
5565 uuid_t agent_uuid;
5566 uuid_copy(agent_uuid, value);
5567 u_int8_t netagent_message_type = 0;
5568 if (type == NECP_CLIENT_PARAMETER_TRIGGER_AGENT) {
5569 netagent_message_type = NETAGENT_MESSAGE_TYPE_CLIENT_TRIGGER;
5570 } else if (type == NECP_CLIENT_PARAMETER_ASSERT_AGENT) {
5571 netagent_message_type = NETAGENT_MESSAGE_TYPE_CLIENT_ASSERT;
5572 } else if (type == NECP_CLIENT_PARAMETER_UNASSERT_AGENT) {
5573 netagent_message_type = NETAGENT_MESSAGE_TYPE_CLIENT_UNASSERT;
5574 }
39037602 5575
0a7de745
A
5576 // Before unasserting, verify that the assertion was already taken
5577 if (type == NECP_CLIENT_PARAMETER_UNASSERT_AGENT) {
5578 if (!necp_client_remove_assertion(client, agent_uuid)) {
5579 error = ENOENT;
39037602
A
5580 break;
5581 }
0a7de745 5582 }
39037602 5583
0a7de745
A
5584 struct necp_client_nexus_parameters parsed_parameters = {};
5585 necp_client_copy_parameters_locked(client, &parsed_parameters);
5586
5587 error = netagent_client_message_with_params(agent_uuid,
5588 client_id,
5589 fd_data->proc_pid,
5590 client->agent_handle,
5591 netagent_message_type,
cb323159 5592 (struct necp_client_agent_parameters *)&parsed_parameters,
0a7de745
A
5593 NULL, NULL);
5594 if (error == 0) {
5595 acted_on_agent = TRUE;
5596 } else {
5597 break;
5598 }
5599
5600 // Only save the assertion if the action succeeded
5601 if (type == NECP_CLIENT_PARAMETER_ASSERT_AGENT) {
5602 necp_client_add_assertion(client, agent_uuid);
39037602 5603 }
0a7de745 5604 }
39037602
A
5605 }
5606
5ba3f43e 5607 offset += sizeof(struct necp_tlv_header) + length;
39037602 5608 }
5ba3f43e
A
5609
5610 NECP_CLIENT_UNLOCK(client);
39037602 5611 }
5ba3f43e 5612 NECP_FD_UNLOCK(fd_data);
39037602
A
5613
5614 if (!acted_on_agent &&
0a7de745 5615 error == 0) {
39037602
A
5616 error = ENOENT;
5617 }
5618done:
5619 *retval = error;
5620 if (parameters != NULL) {
5621 FREE(parameters, M_NECP);
5622 parameters = NULL;
5623 }
5ba3f43e 5624
0a7de745 5625 return error;
39037602
A
5626}
5627
cb323159 5628static NECP_CLIENT_ACTION_FUNCTION int
39037602
A
5629necp_client_copy_agent(__unused struct necp_fd_data *fd_data, struct necp_client_action_args *uap, int *retval)
5630{
5631 int error = 0;
5632 uuid_t agent_uuid;
5633
5634 if (uap->client_id == 0 || uap->client_id_len != sizeof(uuid_t) ||
0a7de745 5635 uap->buffer_size == 0 || uap->buffer == 0) {
39037602
A
5636 NECPLOG0(LOG_ERR, "necp_client_copy_agent bad input");
5637 error = EINVAL;
5638 goto done;
5639 }
5640
5641 error = copyin(uap->client_id, agent_uuid, sizeof(uuid_t));
5642 if (error) {
5643 NECPLOG(LOG_ERR, "necp_client_copy_agent copyin agent_uuid error (%d)", error);
5644 goto done;
5645 }
5646
5647 error = netagent_copyout(agent_uuid, uap->buffer, uap->buffer_size);
5648 if (error) {
5ba3f43e 5649 // netagent_copyout already logs appropriate errors
39037602
A
5650 goto done;
5651 }
5652done:
5653 *retval = error;
5ba3f43e 5654
0a7de745 5655 return error;
39037602
A
5656}
5657
cb323159 5658static NECP_CLIENT_ACTION_FUNCTION int
813fb2f6
A
5659necp_client_agent_use(struct necp_fd_data *fd_data, struct necp_client_action_args *uap, int *retval)
5660{
5661 int error = 0;
813fb2f6
A
5662 struct necp_client *client = NULL;
5663 uuid_t client_id;
5664 struct necp_agent_use_parameters parameters;
5665
5666 if (uap->client_id == 0 || uap->client_id_len != sizeof(uuid_t) ||
0a7de745 5667 uap->buffer_size != sizeof(parameters) || uap->buffer == 0) {
813fb2f6
A
5668 error = EINVAL;
5669 goto done;
5670 }
5671
5672 error = copyin(uap->client_id, client_id, sizeof(uuid_t));
5673 if (error) {
5674 NECPLOG(LOG_ERR, "Copyin client_id error (%d)", error);
5675 goto done;
5676 }
5677
5678 error = copyin(uap->buffer, &parameters, uap->buffer_size);
5679 if (error) {
5680 NECPLOG(LOG_ERR, "Parameters copyin error (%d)", error);
5681 goto done;
5682 }
5683
5ba3f43e
A
5684 NECP_FD_LOCK(fd_data);
5685 client = necp_client_fd_find_client_and_lock(fd_data, client_id);
5686 if (client != NULL) {
813fb2f6 5687 error = netagent_use(parameters.agent_uuid, &parameters.out_use_count);
5ba3f43e 5688 NECP_CLIENT_UNLOCK(client);
813fb2f6
A
5689 } else {
5690 error = ENOENT;
5691 }
5692
5ba3f43e 5693 NECP_FD_UNLOCK(fd_data);
813fb2f6
A
5694
5695 if (error == 0) {
5696 error = copyout(&parameters, uap->buffer, uap->buffer_size);
5697 if (error) {
5698 NECPLOG(LOG_ERR, "Parameters copyout error (%d)", error);
5699 goto done;
5700 }
5701 }
5702
5703done:
5704 *retval = error;
5705
0a7de745 5706 return error;
813fb2f6
A
5707}
5708
cb323159
A
5709struct necp_interface_details_legacy {
5710 char name[IFXNAMSIZ];
5711 u_int32_t index;
5712 u_int32_t generation;
5713 u_int32_t functional_type;
5714 u_int32_t delegate_index;
5715 u_int32_t flags; // see NECP_INTERFACE_FLAG_*
5716 u_int32_t mtu;
5717 struct necp_interface_signature ipv4_signature;
5718 struct necp_interface_signature ipv6_signature;
5719};
5720
5721static NECP_CLIENT_ACTION_FUNCTION int
39037602
A
5722necp_client_copy_interface(__unused struct necp_fd_data *fd_data, struct necp_client_action_args *uap, int *retval)
5723{
5724 int error = 0;
5725 u_int32_t interface_index = 0;
cb323159 5726 struct necp_interface_details interface_details = {};
39037602
A
5727
5728 if (uap->client_id == 0 || uap->client_id_len != sizeof(u_int32_t) ||
cb323159
A
5729 uap->buffer_size < sizeof(struct necp_interface_details_legacy) ||
5730 uap->buffer == 0) {
39037602
A
5731 NECPLOG0(LOG_ERR, "necp_client_copy_interface bad input");
5732 error = EINVAL;
5733 goto done;
5734 }
5735
5736 error = copyin(uap->client_id, &interface_index, sizeof(u_int32_t));
5737 if (error) {
5738 NECPLOG(LOG_ERR, "necp_client_copy_interface copyin interface_index error (%d)", error);
5739 goto done;
5740 }
5741
5742 if (interface_index == 0) {
5743 error = ENOENT;
5744 NECPLOG(LOG_ERR, "necp_client_copy_interface bad interface_index (%d)", interface_index);
5745 goto done;
5746 }
5747
39037602
A
5748 ifnet_head_lock_shared();
5749 ifnet_t interface = NULL;
813fb2f6 5750 if (interface_index != IFSCOPE_NONE && interface_index <= (u_int32_t)if_index) {
39037602
A
5751 interface = ifindex2ifnet[interface_index];
5752 }
5753
5754 if (interface != NULL) {
5755 if (interface->if_xname != NULL) {
5756 strlcpy((char *)&interface_details.name, interface->if_xname, sizeof(interface_details.name));
5757 }
5758 interface_details.index = interface->if_index;
5759 interface_details.generation = ifnet_get_generation(interface);
5760 if (interface->if_delegated.ifp != NULL) {
5761 interface_details.delegate_index = interface->if_delegated.ifp->if_index;
5762 }
5763 interface_details.functional_type = if_functional_type(interface, TRUE);
5764 if (IFNET_IS_EXPENSIVE(interface)) {
5765 interface_details.flags |= NECP_INTERFACE_FLAG_EXPENSIVE;
5766 }
cb323159
A
5767 if (IFNET_IS_CONSTRAINED(interface)) {
5768 interface_details.flags |= NECP_INTERFACE_FLAG_CONSTRAINED;
5769 }
5ba3f43e
A
5770 if ((interface->if_eflags & IFEF_TXSTART) == IFEF_TXSTART) {
5771 interface_details.flags |= NECP_INTERFACE_FLAG_TXSTART;
5772 }
5773 if ((interface->if_eflags & IFEF_NOACKPRI) == IFEF_NOACKPRI) {
5774 interface_details.flags |= NECP_INTERFACE_FLAG_NOACKPRI;
5775 }
d9a64523
A
5776 if ((interface->if_eflags & IFEF_3CA) == IFEF_3CA) {
5777 interface_details.flags |= NECP_INTERFACE_FLAG_3CARRIERAGG;
5778 }
5779 if (IFNET_IS_LOW_POWER(interface)) {
5780 interface_details.flags |= NECP_INTERFACE_FLAG_IS_LOW_POWER;
5781 }
cb323159
A
5782 if (interface->if_xflags & IFXF_MPK_LOG) {
5783 interface_details.flags |= NECP_INTERFACE_FLAG_MPK_LOG;
5784 }
39037602
A
5785 interface_details.mtu = interface->if_mtu;
5786
5ba3f43e 5787 u_int8_t ipv4_signature_len = sizeof(interface_details.ipv4_signature.signature);
39037602 5788 u_int16_t ipv4_signature_flags;
5ba3f43e 5789 if (ifnet_get_netsignature(interface, AF_INET, &ipv4_signature_len, &ipv4_signature_flags,
0a7de745 5790 (u_int8_t *)&interface_details.ipv4_signature) != 0) {
5ba3f43e
A
5791 ipv4_signature_len = 0;
5792 }
5793 interface_details.ipv4_signature.signature_len = ipv4_signature_len;
39037602 5794
5ba3f43e 5795 u_int8_t ipv6_signature_len = sizeof(interface_details.ipv6_signature.signature);
39037602 5796 u_int16_t ipv6_signature_flags;
5ba3f43e 5797 if (ifnet_get_netsignature(interface, AF_INET6, &ipv6_signature_len, &ipv6_signature_flags,
0a7de745 5798 (u_int8_t *)&interface_details.ipv6_signature) != 0) {
5ba3f43e
A
5799 ipv6_signature_len = 0;
5800 }
5801 interface_details.ipv6_signature.signature_len = ipv6_signature_len;
cb323159
A
5802
5803 ifnet_lock_shared(interface);
5804 struct ifaddr *ifa = NULL;
5805 TAILQ_FOREACH(ifa, &interface->if_addrhead, ifa_link) {
5806 IFA_LOCK(ifa);
5807 if (ifa->ifa_addr->sa_family == AF_INET) {
5808 interface_details.flags |= NECP_INTERFACE_FLAG_HAS_NETMASK;
5809 interface_details.ipv4_netmask = ((struct in_ifaddr *)ifa)->ia_sockmask.sin_addr.s_addr;
5810 if (interface->if_flags & IFF_BROADCAST) {
5811 interface_details.flags |= NECP_INTERFACE_FLAG_HAS_BROADCAST;
5812 interface_details.ipv4_broadcast = ((struct in_ifaddr *)ifa)->ia_broadaddr.sin_addr.s_addr;
5813 }
5814 }
5815 IFA_UNLOCK(ifa);
5816 }
5817 ifnet_lock_done(interface);
39037602
A
5818 }
5819
5820 ifnet_head_done();
5821
cb323159
A
5822 // If the client is using an older version of the struct, copy that length
5823 size_t copy_length = sizeof(interface_details);
5824 if (uap->buffer_size < sizeof(struct necp_interface_details_legacy)) {
5825 copy_length = sizeof(struct necp_interface_details_legacy);
5826 }
5827 error = copyout(&interface_details, uap->buffer, copy_length);
39037602
A
5828 if (error) {
5829 NECPLOG(LOG_ERR, "necp_client_copy_interface copyout error (%d)", error);
5830 goto done;
5831 }
5832done:
5833 *retval = error;
5834
0a7de745 5835 return error;
39037602
A
5836}
5837
5ba3f43e 5838
cb323159 5839static NECP_CLIENT_ACTION_FUNCTION int
5ba3f43e 5840necp_client_copy_route_statistics(__unused struct necp_fd_data *fd_data, struct necp_client_action_args *uap, int *retval)
39037602
A
5841{
5842 int error = 0;
5ba3f43e
A
5843 struct necp_client *client = NULL;
5844 uuid_t client_id;
39037602 5845
5ba3f43e 5846 if (uap->client_id == 0 || uap->client_id_len != sizeof(uuid_t) ||
0a7de745 5847 uap->buffer_size < sizeof(struct necp_stat_counts) || uap->buffer == 0) {
5ba3f43e 5848 NECPLOG0(LOG_ERR, "necp_client_copy_route_statistics bad input");
39037602
A
5849 error = EINVAL;
5850 goto done;
5851 }
5852
5ba3f43e 5853 error = copyin(uap->client_id, client_id, sizeof(uuid_t));
39037602 5854 if (error) {
5ba3f43e 5855 NECPLOG(LOG_ERR, "necp_client_copy_route_statistics copyin client_id error (%d)", error);
39037602
A
5856 goto done;
5857 }
5858
5ba3f43e
A
5859 // Lock
5860 NECP_FD_LOCK(fd_data);
5861 client = necp_client_fd_find_client_and_lock(fd_data, client_id);
5862 if (client != NULL) {
5863 NECP_CLIENT_ROUTE_LOCK(client);
a39ff7e2 5864 struct necp_stat_counts route_stats = {};
5ba3f43e 5865 if (client->current_route != NULL && client->current_route->rt_stats != NULL) {
0a7de745 5866 struct nstat_counts *rt_stats = client->current_route->rt_stats;
a39ff7e2
A
5867 atomic_get_64(route_stats.necp_stat_rxpackets, &rt_stats->nstat_rxpackets);
5868 atomic_get_64(route_stats.necp_stat_rxbytes, &rt_stats->nstat_rxbytes);
5869 atomic_get_64(route_stats.necp_stat_txpackets, &rt_stats->nstat_txpackets);
5870 atomic_get_64(route_stats.necp_stat_txbytes, &rt_stats->nstat_txbytes);
5871 route_stats.necp_stat_rxduplicatebytes = rt_stats->nstat_rxduplicatebytes;
5872 route_stats.necp_stat_rxoutoforderbytes = rt_stats->nstat_rxoutoforderbytes;
5873 route_stats.necp_stat_txretransmit = rt_stats->nstat_txretransmit;
5874 route_stats.necp_stat_connectattempts = rt_stats->nstat_connectattempts;
5875 route_stats.necp_stat_connectsuccesses = rt_stats->nstat_connectsuccesses;
5876 route_stats.necp_stat_min_rtt = rt_stats->nstat_min_rtt;
5877 route_stats.necp_stat_avg_rtt = rt_stats->nstat_avg_rtt;
5878 route_stats.necp_stat_var_rtt = rt_stats->nstat_var_rtt;
5879 route_stats.necp_stat_route_flags = client->current_route->rt_flags;
39037602 5880 }
5ba3f43e
A
5881
5882 // Unlock before copying out
5883 NECP_CLIENT_ROUTE_UNLOCK(client);
5884 NECP_CLIENT_UNLOCK(client);
5885 NECP_FD_UNLOCK(fd_data);
5886
5887 error = copyout(&route_stats, uap->buffer, sizeof(route_stats));
5888 if (error) {
5889 NECPLOG(LOG_ERR, "necp_client_copy_route_statistics copyout error (%d)", error);
39037602 5890 }
5ba3f43e
A
5891 } else {
5892 // Unlock
5893 NECP_FD_UNLOCK(fd_data);
5894 error = ENOENT;
39037602 5895 }
39037602 5896
5ba3f43e
A
5897
5898done:
5899 *retval = error;
0a7de745 5900 return error;
39037602
A
5901}
5902
cb323159 5903static NECP_CLIENT_ACTION_FUNCTION int
5ba3f43e 5904necp_client_update_cache(struct necp_fd_data *fd_data, struct necp_client_action_args *uap, int *retval)
39037602
A
5905{
5906 int error = 0;
39037602
A
5907 struct necp_client *client = NULL;
5908 uuid_t client_id;
5909
5910 if (uap->client_id == 0 || uap->client_id_len != sizeof(uuid_t)) {
5911 error = EINVAL;
5912 goto done;
5913 }
5914
5915 error = copyin(uap->client_id, client_id, sizeof(uuid_t));
5916 if (error) {
5ba3f43e 5917 NECPLOG(LOG_ERR, "necp_client_update_cache copyin client_id error (%d)", error);
39037602
A
5918 goto done;
5919 }
5920
5ba3f43e
A
5921 NECP_FD_LOCK(fd_data);
5922 client = necp_client_fd_find_client_and_lock(fd_data, client_id);
5923 if (client == NULL) {
5924 NECP_FD_UNLOCK(fd_data);
5925 error = ENOENT;
5926 goto done;
5927 }
5928
d9a64523
A
5929 struct necp_client_flow_registration *flow_registration = necp_client_find_flow(client, client_id);
5930 if (flow_registration == NULL) {
5931 NECP_CLIENT_UNLOCK(client);
5932 NECP_FD_UNLOCK(fd_data);
5933 error = ENOENT;
5934 goto done;
5935 }
5936
5ba3f43e
A
5937 NECP_CLIENT_ROUTE_LOCK(client);
5938 // This needs to be changed when TFO/ECN is supported by multiple flows
d9a64523 5939 struct necp_client_flow *flow = LIST_FIRST(&flow_registration->flow_list);
5ba3f43e 5940 if (flow == NULL ||
0a7de745
A
5941 (flow->remote_addr.sa.sa_family != AF_INET &&
5942 flow->remote_addr.sa.sa_family != AF_INET6) ||
5943 (flow->local_addr.sa.sa_family != AF_INET &&
5944 flow->local_addr.sa.sa_family != AF_INET6)) {
5ba3f43e
A
5945 error = EINVAL;
5946 NECPLOG(LOG_ERR, "necp_client_update_cache no flow error (%d)", error);
5947 goto done_unlock;
5948 }
5949
5950 necp_cache_buffer cache_buffer;
5951 memset(&cache_buffer, 0, sizeof(cache_buffer));
5952
5953 if (uap->buffer_size != sizeof(necp_cache_buffer) ||
0a7de745 5954 uap->buffer == USER_ADDR_NULL) {
5ba3f43e
A
5955 error = EINVAL;
5956 goto done_unlock;
39037602
A
5957 }
5958
5ba3f43e
A
5959 error = copyin(uap->buffer, &cache_buffer, sizeof(cache_buffer));
5960 if (error) {
5961 NECPLOG(LOG_ERR, "necp_client_update_cache copyin cache buffer error (%d)", error);
5962 goto done_unlock;
5963 }
5964
5965 if (cache_buffer.necp_cache_buf_type == NECP_CLIENT_CACHE_TYPE_ECN &&
5966 cache_buffer.necp_cache_buf_ver == NECP_CLIENT_CACHE_TYPE_ECN_VER_1) {
5967 if (cache_buffer.necp_cache_buf_size != sizeof(necp_tcp_ecn_cache) ||
5968 cache_buffer.necp_cache_buf_addr == USER_ADDR_NULL) {
5969 error = EINVAL;
5970 goto done_unlock;
5971 }
5972
5973 necp_tcp_ecn_cache ecn_cache_buffer;
5974 memset(&ecn_cache_buffer, 0, sizeof(ecn_cache_buffer));
5975
5976 error = copyin(cache_buffer.necp_cache_buf_addr, &ecn_cache_buffer, sizeof(necp_tcp_ecn_cache));
5977 if (error) {
5978 NECPLOG(LOG_ERR, "necp_client_update_cache copyin ecn cache buffer error (%d)", error);
5979 goto done_unlock;
5980 }
5981
5982 if (client->current_route != NULL && client->current_route->rt_ifp != NULL) {
5983 if (!client->platform_binary) {
0a7de745 5984 ecn_cache_buffer.necp_tcp_ecn_heuristics_success = 0;
5ba3f43e
A
5985 }
5986 tcp_heuristics_ecn_update(&ecn_cache_buffer, client->current_route->rt_ifp,
0a7de745 5987 (union sockaddr_in_4_6 *)&flow->local_addr);
5ba3f43e
A
5988 }
5989 } else if (cache_buffer.necp_cache_buf_type == NECP_CLIENT_CACHE_TYPE_TFO &&
0a7de745 5990 cache_buffer.necp_cache_buf_ver == NECP_CLIENT_CACHE_TYPE_TFO_VER_1) {
5ba3f43e
A
5991 if (cache_buffer.necp_cache_buf_size != sizeof(necp_tcp_tfo_cache) ||
5992 cache_buffer.necp_cache_buf_addr == USER_ADDR_NULL) {
5993 error = EINVAL;
5994 goto done_unlock;
5995 }
5996
5997 necp_tcp_tfo_cache tfo_cache_buffer;
5998 memset(&tfo_cache_buffer, 0, sizeof(tfo_cache_buffer));
5999
6000 error = copyin(cache_buffer.necp_cache_buf_addr, &tfo_cache_buffer, sizeof(necp_tcp_tfo_cache));
6001 if (error) {
6002 NECPLOG(LOG_ERR, "necp_client_update_cache copyin tfo cache buffer error (%d)", error);
6003 goto done_unlock;
6004 }
6005
6006 if (client->current_route != NULL && client->current_route->rt_ifp != NULL) {
6007 if (!client->platform_binary) {
0a7de745 6008 tfo_cache_buffer.necp_tcp_tfo_heuristics_success = 0;
5ba3f43e
A
6009 }
6010 tcp_heuristics_tfo_update(&tfo_cache_buffer, client->current_route->rt_ifp,
0a7de745
A
6011 (union sockaddr_in_4_6 *)&flow->local_addr,
6012 (union sockaddr_in_4_6 *)&flow->remote_addr);
5ba3f43e 6013 }
39037602 6014 } else {
0a7de745 6015 error = EINVAL;
39037602 6016 }
5ba3f43e
A
6017done_unlock:
6018 NECP_CLIENT_ROUTE_UNLOCK(client);
6019 NECP_CLIENT_UNLOCK(client);
6020 NECP_FD_UNLOCK(fd_data);
39037602
A
6021done:
6022 *retval = error;
0a7de745 6023 return error;
39037602
A
6024}
6025
cb323159
A
6026#define NECP_CLIENT_ACTION_SIGN_DEFAULT_HOSTNAME_LENGTH 64
6027#define NECP_CLIENT_ACTION_SIGN_MAX_HOSTNAME_LENGTH 1024
6028
6029#define NECP_CLIENT_ACTION_SIGN_TAG_LENGTH 32
6030
6031static NECP_CLIENT_ACTION_FUNCTION int
6032necp_client_sign(__unused struct necp_fd_data *fd_data, struct necp_client_action_args *uap, int *retval)
6033{
6034 int error = 0;
6035 u_int32_t hostname_length = 0;
6036 u_int8_t tag[NECP_CLIENT_ACTION_SIGN_TAG_LENGTH] = {};
6037 struct necp_client_signable signable = {};
6038 union necp_sockaddr_union address_answer = {};
6039 u_int8_t *client_hostname = NULL;
6040 u_int8_t *allocated_hostname = NULL;
6041 u_int8_t default_hostname[NECP_CLIENT_ACTION_SIGN_DEFAULT_HOSTNAME_LENGTH] = "";
6042 uint32_t tag_size = sizeof(tag);
6043
6044 *retval = 0;
6045
6046 const bool has_resolver_entitlement = (priv_check_cred(kauth_cred_get(), PRIV_NET_VALIDATED_RESOLVER, 0) == 0);
6047 if (!has_resolver_entitlement) {
6048 NECPLOG0(LOG_ERR, "Process does not hold the necessary entitlement to sign resolver answers");
6049 error = EPERM;
6050 goto done;
6051 }
6052
6053 if (uap->client_id == 0 || uap->client_id_len < sizeof(struct necp_client_signable)) {
6054 error = EINVAL;
6055 goto done;
6056 }
6057
6058 if (uap->buffer == 0 || uap->buffer_size != NECP_CLIENT_ACTION_SIGN_TAG_LENGTH) {
6059 error = EINVAL;
6060 goto done;
6061 }
6062
6063 error = copyin(uap->client_id, &signable, sizeof(signable));
6064 if (error) {
6065 NECPLOG(LOG_ERR, "necp_client_sign copyin signable error (%d)", error);
6066 goto done;
6067 }
6068
6069 if (signable.sign_type != NECP_CLIENT_SIGN_TYPE_RESOLVER_ANSWER) {
6070 NECPLOG(LOG_ERR, "necp_client_sign unknown signable type (%u)", signable.sign_type);
6071 error = EINVAL;
6072 goto done;
6073 }
6074
6075 if (uap->client_id_len < sizeof(struct necp_client_resolver_answer)) {
6076 error = EINVAL;
6077 goto done;
6078 }
6079
6080 error = copyin(uap->client_id + sizeof(signable), &address_answer, sizeof(address_answer));
6081 if (error) {
6082 NECPLOG(LOG_ERR, "necp_client_sign copyin address_answer error (%d)", error);
6083 goto done;
6084 }
6085
6086 error = copyin(uap->client_id + sizeof(signable) + sizeof(address_answer), &hostname_length, sizeof(hostname_length));
6087 if (error) {
6088 NECPLOG(LOG_ERR, "necp_client_sign copyin hostname_length error (%d)", error);
6089 goto done;
6090 }
6091
6092 if (hostname_length > NECP_CLIENT_ACTION_SIGN_MAX_HOSTNAME_LENGTH) {
6093 error = EINVAL;
6094 goto done;
6095 }
6096
6097 if (hostname_length > NECP_CLIENT_ACTION_SIGN_DEFAULT_HOSTNAME_LENGTH) {
6098 if ((allocated_hostname = _MALLOC(hostname_length, M_NECP, M_WAITOK | M_ZERO)) == NULL) {
6099 NECPLOG(LOG_ERR, "necp_client_sign malloc hostname %u failed", hostname_length);
6100 error = ENOMEM;
6101 goto done;
6102 }
6103
6104 client_hostname = allocated_hostname;
6105 } else {
6106 client_hostname = default_hostname;
6107 }
6108
6109 error = copyin(uap->client_id + sizeof(signable) + sizeof(address_answer) + sizeof(hostname_length), client_hostname, hostname_length);
6110 if (error) {
6111 NECPLOG(LOG_ERR, "necp_client_sign copyin hostname error (%d)", error);
6112 goto done;
6113 }
6114
6115 address_answer.sin.sin_port = 0;
6116 error = necp_sign_resolver_answer(signable.client_id, client_hostname, hostname_length,
6117 (u_int8_t *)&address_answer, sizeof(address_answer),
6118 tag, &tag_size);
6119 if (tag_size != sizeof(tag)) {
6120 NECPLOG(LOG_ERR, "necp_client_sign unexpected tag size %u", tag_size);
6121 error = EINVAL;
6122 goto done;
6123 }
6124 error = copyout(tag, uap->buffer, tag_size);
6125 if (error) {
6126 NECPLOG(LOG_ERR, "necp_client_sign copyout error (%d)", error);
6127 goto done;
6128 }
6129
6130done:
6131 if (allocated_hostname != NULL) {
6132 FREE(allocated_hostname, M_NECP);
6133 allocated_hostname = NULL;
6134 }
6135 *retval = error;
6136 return error;
6137}
6138
39037602
A
6139int
6140necp_client_action(struct proc *p, struct necp_client_action_args *uap, int *retval)
6141{
6142#pragma unused(p)
6143 int error = 0;
6144 int return_value = 0;
6145 struct necp_fd_data *fd_data = NULL;
6146 error = necp_find_fd_data(uap->necp_fd, &fd_data);
6147 if (error != 0) {
6148 NECPLOG(LOG_ERR, "necp_client_action find fd error (%d)", error);
0a7de745 6149 return error;
39037602
A
6150 }
6151
6152 u_int32_t action = uap->action;
6153 switch (action) {
0a7de745
A
6154 case NECP_CLIENT_ACTION_ADD: {
6155 return_value = necp_client_add(p, fd_data, uap, retval);
6156 break;
6157 }
cb323159
A
6158 case NECP_CLIENT_ACTION_CLAIM: {
6159 return_value = necp_client_claim(p, fd_data, uap, retval);
6160 break;
6161 }
0a7de745
A
6162 case NECP_CLIENT_ACTION_REMOVE: {
6163 return_value = necp_client_remove(fd_data, uap, retval);
6164 break;
6165 }
6166 case NECP_CLIENT_ACTION_COPY_PARAMETERS:
6167 case NECP_CLIENT_ACTION_COPY_RESULT:
6168 case NECP_CLIENT_ACTION_COPY_UPDATED_RESULT: {
6169 return_value = necp_client_copy(fd_data, uap, retval);
6170 break;
6171 }
6172 case NECP_CLIENT_ACTION_COPY_LIST: {
6173 return_value = necp_client_list(fd_data, uap, retval);
6174 break;
6175 }
6176 case NECP_CLIENT_ACTION_AGENT: {
6177 return_value = necp_client_agent_action(fd_data, uap, retval);
6178 break;
6179 }
6180 case NECP_CLIENT_ACTION_COPY_AGENT: {
6181 return_value = necp_client_copy_agent(fd_data, uap, retval);
6182 break;
6183 }
6184 case NECP_CLIENT_ACTION_AGENT_USE: {
6185 return_value = necp_client_agent_use(fd_data, uap, retval);
6186 break;
6187 }
6188 case NECP_CLIENT_ACTION_COPY_INTERFACE: {
6189 return_value = necp_client_copy_interface(fd_data, uap, retval);
6190 break;
6191 }
6192 case NECP_CLIENT_ACTION_COPY_ROUTE_STATISTICS: {
6193 return_value = necp_client_copy_route_statistics(fd_data, uap, retval);
6194 break;
6195 }
6196 case NECP_CLIENT_ACTION_UPDATE_CACHE: {
6197 return_value = necp_client_update_cache(fd_data, uap, retval);
6198 break;
6199 }
6200 case NECP_CLIENT_ACTION_COPY_CLIENT_UPDATE: {
6201 return_value = necp_client_copy_client_update(fd_data, uap, retval);
6202 break;
6203 }
cb323159
A
6204 case NECP_CLIENT_ACTION_SIGN: {
6205 return_value = necp_client_sign(fd_data, uap, retval);
6206 break;
6207 }
0a7de745
A
6208 default: {
6209 NECPLOG(LOG_ERR, "necp_client_action unknown action (%u)", action);
6210 return_value = EINVAL;
6211 break;
6212 }
39037602
A
6213 }
6214
6215 file_drop(uap->necp_fd);
6216
0a7de745 6217 return return_value;
39037602
A
6218}
6219
6220#define NECP_MAX_MATCH_POLICY_PARAMETER_SIZE 1024
6221
6222int
6223necp_match_policy(struct proc *p, struct necp_match_policy_args *uap, int32_t *retval)
6224{
6225#pragma unused(retval)
6226 u_int8_t *parameters = NULL;
d9a64523 6227 struct necp_aggregate_result returned_result;
39037602
A
6228 int error = 0;
6229
6230 if (uap == NULL) {
6231 error = EINVAL;
6232 goto done;
6233 }
6234
6235 if (uap->parameters == 0 || uap->parameters_size == 0 || uap->parameters_size > NECP_MAX_MATCH_POLICY_PARAMETER_SIZE || uap->returned_result == 0) {
6236 error = EINVAL;
6237 goto done;
6238 }
6239
6240 MALLOC(parameters, u_int8_t *, uap->parameters_size, M_NECP, M_WAITOK | M_ZERO);
6241 if (parameters == NULL) {
6242 error = ENOMEM;
6243 goto done;
6244 }
6245 // Copy parameters in
6246 error = copyin(uap->parameters, parameters, uap->parameters_size);
6247 if (error) {
6248 goto done;
6249 }
6250
5ba3f43e 6251 error = necp_application_find_policy_match_internal(p, parameters, uap->parameters_size,
ea3f0419 6252 &returned_result, NULL, NULL, 0, NULL, NULL, NULL, NULL, NULL, false, false, NULL);
39037602
A
6253 if (error) {
6254 goto done;
6255 }
6256
6257 // Copy return value back
6258 error = copyout(&returned_result, uap->returned_result, sizeof(struct necp_aggregate_result));
6259 if (error) {
6260 goto done;
6261 }
6262done:
6263 if (parameters != NULL) {
6264 FREE(parameters, M_NECP);
6265 }
0a7de745 6266 return error;
39037602
A
6267}
6268
6269/// Socket operations
6270#define NECP_MAX_SOCKET_ATTRIBUTE_STRING_LENGTH 253
6271
6272static bool
6273necp_set_socket_attribute(u_int8_t *buffer, size_t buffer_length, u_int8_t type, char **buffer_p)
6274{
6275 int error = 0;
6276 int cursor = 0;
6277 size_t string_size = 0;
6278 char *local_string = NULL;
6279 u_int8_t *value = NULL;
6280
cb323159 6281 cursor = necp_buffer_find_tlv(buffer, buffer_length, 0, type, NULL, 0);
39037602
A
6282 if (cursor < 0) {
6283 // This will clear out the parameter
6284 goto done;
6285 }
6286
6287 string_size = necp_buffer_get_tlv_length(buffer, cursor);
6288 if (string_size == 0 || string_size > NECP_MAX_SOCKET_ATTRIBUTE_STRING_LENGTH) {
6289 // This will clear out the parameter
6290 goto done;
6291 }
6292
6293 MALLOC(local_string, char *, string_size + 1, M_NECP, M_WAITOK | M_ZERO);
6294 if (local_string == NULL) {
6295 NECPLOG(LOG_ERR, "Failed to allocate a socket attribute buffer (size %d)", string_size);
6296 goto fail;
6297 }
6298
6299 value = necp_buffer_get_tlv_value(buffer, cursor, NULL);
6300 if (value == NULL) {
6301 NECPLOG0(LOG_ERR, "Failed to get socket attribute");
6302 goto fail;
6303 }
6304
6305 memcpy(local_string, value, string_size);
6306 local_string[string_size] = 0;
6307
6308done:
6309 if (*buffer_p != NULL) {
6310 FREE(*buffer_p, M_NECP);
6311 *buffer_p = NULL;
6312 }
6313
6314 *buffer_p = local_string;
0a7de745 6315 return 0;
39037602
A
6316fail:
6317 if (local_string != NULL) {
6318 FREE(local_string, M_NECP);
6319 }
0a7de745 6320 return error;
39037602
A
6321}
6322
6323errno_t
6324necp_set_socket_attributes(struct socket *so, struct sockopt *sopt)
6325{
6326 int error = 0;
6327 u_int8_t *buffer = NULL;
6328 struct inpcb *inp = NULL;
6329
6330 if ((SOCK_DOM(so) != PF_INET
6331#if INET6
0a7de745 6332 && SOCK_DOM(so) != PF_INET6
39037602 6333#endif
0a7de745 6334 )) {
39037602
A
6335 error = EINVAL;
6336 goto done;
6337 }
6338
6339 inp = sotoinpcb(so);
6340
6341 size_t valsize = sopt->sopt_valsize;
6342 if (valsize == 0 ||
0a7de745 6343 valsize > ((sizeof(struct necp_tlv_header) + NECP_MAX_SOCKET_ATTRIBUTE_STRING_LENGTH) * 2)) {
39037602
A
6344 goto done;
6345 }
6346
6347 MALLOC(buffer, u_int8_t *, valsize, M_NECP, M_WAITOK | M_ZERO);
6348 if (buffer == NULL) {
6349 goto done;
6350 }
6351
6352 error = sooptcopyin(sopt, buffer, valsize, 0);
6353 if (error) {
6354 goto done;
6355 }
6356
6357 error = necp_set_socket_attribute(buffer, valsize, NECP_TLV_ATTRIBUTE_DOMAIN, &inp->inp_necp_attributes.inp_domain);
6358 if (error) {
6359 NECPLOG0(LOG_ERR, "Could not set domain TLV for socket attributes");
6360 goto done;
6361 }
6362
6363 error = necp_set_socket_attribute(buffer, valsize, NECP_TLV_ATTRIBUTE_ACCOUNT, &inp->inp_necp_attributes.inp_account);
6364 if (error) {
6365 NECPLOG0(LOG_ERR, "Could not set account TLV for socket attributes");
6366 goto done;
6367 }
6368
6369 if (necp_debug) {
6370 NECPLOG(LOG_DEBUG, "Set on socket: Domain %s, Account %s", inp->inp_necp_attributes.inp_domain, inp->inp_necp_attributes.inp_account);
6371 }
6372done:
6373 if (buffer != NULL) {
6374 FREE(buffer, M_NECP);
6375 }
6376
0a7de745 6377 return error;
39037602
A
6378}
6379
6380errno_t
6381necp_get_socket_attributes(struct socket *so, struct sockopt *sopt)
6382{
6383 int error = 0;
6384 u_int8_t *buffer = NULL;
6385 u_int8_t *cursor = NULL;
6386 size_t valsize = 0;
5c9f4661 6387 struct inpcb *inp = NULL;
39037602 6388
5c9f4661
A
6389 if ((SOCK_DOM(so) != PF_INET
6390#if INET6
0a7de745 6391 && SOCK_DOM(so) != PF_INET6
5c9f4661 6392#endif
0a7de745 6393 )) {
5c9f4661
A
6394 error = EINVAL;
6395 goto done;
6396 }
6397
6398 inp = sotoinpcb(so);
39037602 6399 if (inp->inp_necp_attributes.inp_domain != NULL) {
5ba3f43e 6400 valsize += sizeof(struct necp_tlv_header) + strlen(inp->inp_necp_attributes.inp_domain);
39037602
A
6401 }
6402 if (inp->inp_necp_attributes.inp_account != NULL) {
5ba3f43e 6403 valsize += sizeof(struct necp_tlv_header) + strlen(inp->inp_necp_attributes.inp_account);
39037602
A
6404 }
6405 if (valsize == 0) {
6406 goto done;
6407 }
6408
6409 MALLOC(buffer, u_int8_t *, valsize, M_NECP, M_WAITOK | M_ZERO);
6410 if (buffer == NULL) {
6411 goto done;
6412 }
6413
6414 cursor = buffer;
6415 if (inp->inp_necp_attributes.inp_domain != NULL) {
5ba3f43e 6416 cursor = necp_buffer_write_tlv(cursor, NECP_TLV_ATTRIBUTE_DOMAIN, strlen(inp->inp_necp_attributes.inp_domain), inp->inp_necp_attributes.inp_domain,
0a7de745 6417 buffer, valsize);
39037602
A
6418 }
6419
6420 if (inp->inp_necp_attributes.inp_account != NULL) {
5ba3f43e 6421 cursor = necp_buffer_write_tlv(cursor, NECP_TLV_ATTRIBUTE_ACCOUNT, strlen(inp->inp_necp_attributes.inp_account), inp->inp_necp_attributes.inp_account,
0a7de745 6422 buffer, valsize);
39037602
A
6423 }
6424
6425 error = sooptcopyout(sopt, buffer, valsize);
6426 if (error) {
6427 goto done;
6428 }
6429done:
6430 if (buffer != NULL) {
6431 FREE(buffer, M_NECP);
6432 }
5ba3f43e 6433
0a7de745 6434 return error;
39037602
A
6435}
6436
5ba3f43e
A
6437void *
6438necp_create_nexus_assign_message(uuid_t nexus_instance, u_int32_t nexus_port, void *key, uint32_t key_length,
cb323159 6439 struct necp_client_endpoint *local_endpoint, struct necp_client_endpoint *remote_endpoint, struct ether_addr *local_ether_addr,
0a7de745 6440 u_int32_t flow_adv_index, void *flow_stats, size_t *message_length)
5ba3f43e
A
6441{
6442 u_int8_t *buffer = NULL;
6443 u_int8_t *cursor = NULL;
6444 size_t valsize = 0;
6445 bool has_nexus_assignment = FALSE;
6446
5ba3f43e
A
6447 if (!uuid_is_null(nexus_instance)) {
6448 has_nexus_assignment = TRUE;
6449 valsize += sizeof(struct necp_tlv_header) + sizeof(uuid_t);
6450 valsize += sizeof(struct necp_tlv_header) + sizeof(u_int32_t);
6451 }
6452 if (flow_adv_index != NECP_FLOWADV_IDX_INVALID) {
6453 valsize += sizeof(struct necp_tlv_header) + sizeof(u_int32_t);
6454 }
6455 if (key != NULL && key_length > 0) {
6456 valsize += sizeof(struct necp_tlv_header) + key_length;
6457 }
6458 if (local_endpoint != NULL) {
6459 valsize += sizeof(struct necp_tlv_header) + sizeof(struct necp_client_endpoint);
6460 }
6461 if (remote_endpoint != NULL) {
6462 valsize += sizeof(struct necp_tlv_header) + sizeof(struct necp_client_endpoint);
6463 }
cb323159
A
6464 if (local_ether_addr != NULL) {
6465 valsize += sizeof(struct necp_tlv_header) + sizeof(struct ether_addr);
6466 }
d9a64523
A
6467 if (flow_stats != NULL) {
6468 valsize += sizeof(struct necp_tlv_header) + sizeof(void *);
6469 }
5ba3f43e 6470 if (valsize == 0) {
0a7de745 6471 return NULL;
5ba3f43e
A
6472 }
6473
6474 MALLOC(buffer, u_int8_t *, valsize, M_NETAGENT, M_WAITOK | M_ZERO); // Use M_NETAGENT area, since it is expected upon free
6475 if (buffer == NULL) {
0a7de745 6476 return NULL;
5ba3f43e
A
6477 }
6478
6479 cursor = buffer;
6480 if (has_nexus_assignment) {
6481 cursor = necp_buffer_write_tlv(cursor, NECP_CLIENT_RESULT_NEXUS_INSTANCE, sizeof(uuid_t), nexus_instance, buffer, valsize);
6482 cursor = necp_buffer_write_tlv(cursor, NECP_CLIENT_RESULT_NEXUS_PORT, sizeof(u_int32_t), &nexus_port, buffer, valsize);
6483 }
6484 if (flow_adv_index != NECP_FLOWADV_IDX_INVALID) {
6485 cursor = necp_buffer_write_tlv(cursor, NECP_CLIENT_RESULT_NEXUS_PORT_FLOW_INDEX, sizeof(u_int32_t), &flow_adv_index, buffer, valsize);
6486 }
6487 if (key != NULL && key_length > 0) {
6488 cursor = necp_buffer_write_tlv(cursor, NECP_CLIENT_PARAMETER_NEXUS_KEY, key_length, key, buffer, valsize);
6489 }
6490 if (local_endpoint != NULL) {
6491 cursor = necp_buffer_write_tlv(cursor, NECP_CLIENT_RESULT_LOCAL_ENDPOINT, sizeof(struct necp_client_endpoint), local_endpoint, buffer, valsize);
6492 }
6493 if (remote_endpoint != NULL) {
6494 cursor = necp_buffer_write_tlv(cursor, NECP_CLIENT_RESULT_REMOTE_ENDPOINT, sizeof(struct necp_client_endpoint), remote_endpoint, buffer, valsize);
6495 }
cb323159
A
6496 if (local_ether_addr != NULL) {
6497 cursor = necp_buffer_write_tlv(cursor, NECP_CLIENT_RESULT_LOCAL_ETHER_ADDR, sizeof(struct ether_addr), local_ether_addr, buffer, valsize);
6498 }
d9a64523
A
6499 if (flow_stats != NULL) {
6500 cursor = necp_buffer_write_tlv(cursor, NECP_CLIENT_RESULT_NEXUS_FLOW_STATS, sizeof(void *), &flow_stats, buffer, valsize);
6501 }
5ba3f43e
A
6502
6503 *message_length = valsize;
6504
0a7de745 6505 return buffer;
5ba3f43e
A
6506}
6507
6508void
6509necp_inpcb_remove_cb(struct inpcb *inp)
6510{
6511 if (!uuid_is_null(inp->necp_client_uuid)) {
6512 necp_client_unregister_socket_flow(inp->necp_client_uuid, inp);
6513 uuid_clear(inp->necp_client_uuid);
6514 }
6515}
6516
39037602
A
6517void
6518necp_inpcb_dispose(struct inpcb *inp)
6519{
a39ff7e2 6520 necp_inpcb_remove_cb(inp); // Clear out socket registrations if not yet done
39037602
A
6521 if (inp->inp_necp_attributes.inp_domain != NULL) {
6522 FREE(inp->inp_necp_attributes.inp_domain, M_NECP);
6523 inp->inp_necp_attributes.inp_domain = NULL;
6524 }
6525 if (inp->inp_necp_attributes.inp_account != NULL) {
6526 FREE(inp->inp_necp_attributes.inp_account, M_NECP);
6527 inp->inp_necp_attributes.inp_account = NULL;
6528 }
6529}
6530
5ba3f43e
A
6531void
6532necp_mppcb_dispose(struct mppcb *mpp)
6533{
6534 if (!uuid_is_null(mpp->necp_client_uuid)) {
6535 necp_client_unregister_multipath_cb(mpp->necp_client_uuid, mpp);
6536 uuid_clear(mpp->necp_client_uuid);
6537 }
6538}
6539
39037602
A
6540/// Module init
6541
6542errno_t
6543necp_client_init(void)
6544{
39037602
A
6545 necp_fd_grp_attr = lck_grp_attr_alloc_init();
6546 if (necp_fd_grp_attr == NULL) {
a39ff7e2
A
6547 panic("lck_grp_attr_alloc_init failed\n");
6548 /* NOTREACHED */
39037602
A
6549 }
6550
6551 necp_fd_mtx_grp = lck_grp_alloc_init("necp_fd", necp_fd_grp_attr);
6552 if (necp_fd_mtx_grp == NULL) {
a39ff7e2
A
6553 panic("lck_grp_alloc_init failed\n");
6554 /* NOTREACHED */
39037602
A
6555 }
6556
6557 necp_fd_mtx_attr = lck_attr_alloc_init();
6558 if (necp_fd_mtx_attr == NULL) {
a39ff7e2
A
6559 panic("lck_attr_alloc_init failed\n");
6560 /* NOTREACHED */
39037602
A
6561 }
6562
5ba3f43e
A
6563 necp_client_fd_size = sizeof(struct necp_fd_data);
6564 necp_client_fd_zone = zinit(necp_client_fd_size,
0a7de745
A
6565 NECP_CLIENT_FD_ZONE_MAX * necp_client_fd_size,
6566 0, NECP_CLIENT_FD_ZONE_NAME);
5ba3f43e 6567 if (necp_client_fd_zone == NULL) {
a39ff7e2
A
6568 panic("zinit(necp_client_fd) failed\n");
6569 /* NOTREACHED */
5ba3f43e
A
6570 }
6571
6572 necp_flow_size = sizeof(struct necp_client_flow);
0a7de745 6573 necp_flow_cache = mcache_create(NECP_FLOW_ZONE_NAME, necp_flow_size, sizeof(uint64_t), 0, MCR_SLEEP);
a39ff7e2
A
6574 if (necp_flow_cache == NULL) {
6575 panic("mcache_create(necp_flow_cache) failed\n");
6576 /* NOTREACHED */
39037602
A
6577 }
6578
d9a64523 6579 necp_flow_registration_size = sizeof(struct necp_client_flow_registration);
0a7de745 6580 necp_flow_registration_cache = mcache_create(NECP_FLOW_REGISTRATION_ZONE_NAME, necp_flow_registration_size, sizeof(uint64_t), 0, MCR_SLEEP);
d9a64523
A
6581 if (necp_flow_registration_cache == NULL) {
6582 panic("mcache_create(necp_client_flow_registration) failed\n");
6583 /* NOTREACHED */
6584 }
6585
5ba3f43e 6586 necp_client_update_tcall = thread_call_allocate_with_options(necp_update_all_clients_callout, NULL,
0a7de745 6587 THREAD_CALL_PRIORITY_KERNEL, THREAD_CALL_OPTIONS_ONCE);
5ba3f43e
A
6588 VERIFY(necp_client_update_tcall != NULL);
6589
39037602 6590 lck_rw_init(&necp_fd_lock, necp_fd_mtx_grp, necp_fd_mtx_attr);
5ba3f43e
A
6591 lck_rw_init(&necp_observer_lock, necp_fd_mtx_grp, necp_fd_mtx_attr);
6592 lck_rw_init(&necp_client_tree_lock, necp_fd_mtx_grp, necp_fd_mtx_attr);
0a7de745 6593 lck_rw_init(&necp_flow_tree_lock, necp_fd_mtx_grp, necp_fd_mtx_attr);
5ba3f43e 6594 lck_rw_init(&necp_collect_stats_list_lock, necp_fd_mtx_grp, necp_fd_mtx_attr);
39037602
A
6595
6596 LIST_INIT(&necp_fd_list);
5ba3f43e 6597 LIST_INIT(&necp_fd_observer_list);
d9a64523 6598 LIST_INIT(&necp_collect_stats_flow_list);
5ba3f43e
A
6599
6600 RB_INIT(&necp_client_global_tree);
d9a64523 6601 RB_INIT(&necp_client_flow_global_tree);
39037602 6602
0a7de745 6603 return 0;
a39ff7e2
A
6604}
6605
6606void
6607necp_client_reap_caches(boolean_t purge)
6608{
6609 mcache_reap_now(necp_flow_cache, purge);
d9a64523 6610 mcache_reap_now(necp_flow_registration_cache, purge);
39037602 6611}
a39ff7e2 6612