xref: /xnu-12377.1.9/bsd/net/network_agent.c (revision f6217f891ac0bb64f3d375211650a4c1ff8ca1ea)
1 /*
2  * Copyright (c) 2014-2024 Apple Inc. All rights reserved.
3  *
4  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5  *
6  * This file contains Original Code and/or Modifications of Original Code
7  * as defined in and that are subject to the Apple Public Source License
8  * Version 2.0 (the 'License'). You may not use this file except in
9  * compliance with the License. The rights granted to you under the License
10  * may not be used to create, or enable the creation or redistribution of,
11  * unlawful or unlicensed copies of an Apple operating system, or to
12  * circumvent, violate, or enable the circumvention or violation of, any
13  * terms of an Apple operating system software license agreement.
14  *
15  * Please obtain a copy of the License at
16  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17  *
18  * The Original Code and all software distributed under the License are
19  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23  * Please see the License for the specific language governing rights and
24  * limitations under the License.
25  *
26  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27  */
28 
29 #include <string.h>
30 #include <sys/systm.h>
31 #include <sys/types.h>
32 #include <sys/syslog.h>
33 #include <sys/queue.h>
34 #include <sys/malloc.h>
35 #include <sys/kernel.h>
36 #include <sys/kern_control.h>
37 #include <sys/mbuf.h>
38 #include <sys/kpi_mbuf.h>
39 #include <sys/sysctl.h>
40 #include <sys/priv.h>
41 #include <sys/kern_event.h>
42 #include <sys/sysproto.h>
43 #include <net/network_agent.h>
44 #include <net/if_var.h>
45 #include <net/necp.h>
46 #include <os/log.h>
47 
48 u_int32_t netagent_debug = LOG_NOTICE; // 0=None, 1=Basic
49 
50 SYSCTL_NODE(_net, OID_AUTO, netagent, CTLFLAG_RW | CTLFLAG_LOCKED, 0, "NetworkAgent");
51 SYSCTL_INT(_net_netagent, OID_AUTO, debug, CTLFLAG_LOCKED | CTLFLAG_RW, &netagent_debug, 0, "");
52 
53 static int netagent_registered_count = 0;
54 SYSCTL_INT(_net_netagent, OID_AUTO, registered_count, CTLFLAG_RD | CTLFLAG_LOCKED,
55     &netagent_registered_count, 0, "");
56 
57 static int netagent_active_count = 0;
58 SYSCTL_INT(_net_netagent, OID_AUTO, active_count, CTLFLAG_RD | CTLFLAG_LOCKED,
59     &netagent_active_count, 0, "");
60 
61 #define NETAGENTLOG(level, format, ...) do {                                             \
62     if (level <= netagent_debug) {                                                       \
63 	if (level == LOG_ERR) {                                                          \
64 	    os_log_error(OS_LOG_DEFAULT, "%s: " format "\n", __FUNCTION__, __VA_ARGS__); \
65 	} else {                                                                         \
66 	    os_log(OS_LOG_DEFAULT, "%s: " format "\n", __FUNCTION__, __VA_ARGS__);       \
67 	}                                                                                \
68     }                                                                                    \
69 } while (0)
70 
71 #define NETAGENTLOG0(level, msg) do {                                                    \
72     if (level <= netagent_debug) {                                                       \
73 	        if (level == LOG_ERR) {                                                          \
74 	    os_log_error(OS_LOG_DEFAULT, "%s: %s\n", __FUNCTION__, msg);                 \
75 	} else {                                                                         \
76 	    os_log(OS_LOG_DEFAULT, "%s: %s\n", __FUNCTION__, msg);                       \
77 	}                                                                                \
78     }                                                                                    \
79 } while (0)
80 
81 #if __has_ptrcheck
82 static inline
83 __attribute__((always_inline)) __pure
84 uint8_t * __bidi_indexable
netagent_get_data(const struct netagent * agent)85 netagent_get_data(const struct netagent *agent)
86 {
87 	if (agent == NULL) {
88 		return NULL;
89 	}
90 
91 	return __unsafe_forge_bidi_indexable(uint8_t *, agent->netagent_data, agent->netagent_data_size);
92 }
93 #else
94 #define netagent_get_data(agent) ((agent)->netagent_data)
95 #endif
96 
97 #if __has_ptrcheck
98 static inline
99 __attribute__((always_inline)) __pure
100 uint8_t * __bidi_indexable
netagent_group_message_get_members(const struct netagent_client_group_message * msg,size_t members_length)101 netagent_group_message_get_members(const struct netagent_client_group_message *msg, size_t members_length)
102 {
103 	if (msg == NULL) {
104 		return NULL;
105 	}
106 
107 	return __unsafe_forge_bidi_indexable(uint8_t *, msg->group_members, members_length);
108 }
109 #else
110 #define netagent_group_message_get_members(msg, members_length) ((msg)->group_members)
111 #endif
112 
113 #if __has_ptrcheck
114 static inline
115 __attribute__((always_inline)) __pure
116 uint8_t * __bidi_indexable
netagent_assign_message_get_necp_result(const struct netagent_assign_nexus_message * msg,size_t result_length)117 netagent_assign_message_get_necp_result(const struct netagent_assign_nexus_message *msg, size_t result_length)
118 {
119 	if (msg == NULL) {
120 		return NULL;
121 	}
122 
123 	return __unsafe_forge_bidi_indexable(uint8_t *, msg->assign_necp_results, result_length);
124 }
125 #else
126 #define netagent_assign_message_get_necp_result(msg, result_length) ((msg)->assign_necp_results)
127 #endif
128 
129 struct netagent_client {
130 	LIST_ENTRY(netagent_client) client_chain;
131 	uuid_t client_id;
132 	uuid_t client_proc_uuid;
133 	pid_t client_pid;
134 };
135 
136 LIST_HEAD(netagent_client_list_s, netagent_client);
137 
138 struct netagent_token {
139 	TAILQ_ENTRY(netagent_token) token_chain;
140 	u_int32_t token_length;
141 	u_int8_t *  __indexable token_bytes;
142 };
143 
144 TAILQ_HEAD(netagent_token_list_s, netagent_token);
145 
146 #define NETAGENT_MAX_CLIENT_ERROR_COUNT 32
147 
148 struct netagent_registration {
149 	LIST_ENTRY(netagent_registration) global_chain;
150 	TAILQ_ENTRY(netagent_registration) session_chain;
151 	lck_rw_t agent_lock;
152 	u_int32_t control_unit;
153 	netagent_event_f event_handler;
154 	void *event_context;
155 	u_int32_t generation;
156 	u_int64_t use_count;
157 	u_int64_t need_tokens_event_deadline;
158 	u_int32_t token_count;
159 	u_int32_t token_low_water;
160 	int32_t last_client_error;
161 	u_int32_t client_error_count;
162 	u_int8_t allow_multiple_registrations;
163 	u_int8_t __pad_bytes[2];
164 	struct netagent_token_list_s token_list;
165 	struct netagent_client_list_s pending_triggers_list;
166 	size_t netagent_alloc_size;
167 	struct netagent *netagent __sized_by(netagent_alloc_size);
168 };
169 
170 struct netagent_session {
171 	u_int32_t control_unit; // A control unit of 0 indicates an agent owned by the kernel
172 	lck_mtx_t session_lock;
173 	TAILQ_HEAD(_netagent_registration_list, netagent_registration) registrations;
174 
175 	netagent_event_f event_handler;
176 	void *event_context;
177 	bool allow_multiple_registrations;
178 };
179 
180 typedef enum {
181 	kNetagentErrorDomainPOSIX                       = 0,
182 	kNetagentErrorDomainUserDefined         = 1,
183 } netagent_error_domain_t;
184 
185 static LIST_HEAD(_netagent_list, netagent_registration) shared_netagent_list =
186     LIST_HEAD_INITIALIZER(master_netagent_list);
187 
188 // Protected by netagent_list_lock
189 static u_int32_t g_next_generation = 1;
190 
191 static kern_ctl_ref     netagent_kctlref;
192 static u_int32_t        netagent_family;
193 static LCK_GRP_DECLARE(netagent_mtx_grp, NETAGENT_CONTROL_NAME);
194 static LCK_RW_DECLARE(netagent_list_lock, &netagent_mtx_grp);
195 
196 #define NETAGENT_LIST_LOCK_EXCLUSIVE() lck_rw_lock_exclusive(&netagent_list_lock)
197 #define NETAGENT_LIST_LOCK_SHARED() lck_rw_lock_shared(&netagent_list_lock)
198 #define NETAGENT_LIST_UNLOCK() lck_rw_done(&netagent_list_lock)
199 #define NETAGENT_LIST_ASSERT_LOCKED() LCK_RW_ASSERT(&netagent_list_lock, LCK_RW_ASSERT_HELD)
200 
201 #define NETAGENT_SESSION_LOCK(session) lck_mtx_lock(&session->session_lock)
202 #define NETAGENT_SESSION_UNLOCK(session) lck_mtx_unlock(&session->session_lock)
203 #define NETAGENT_SESSION_ASSERT_LOCKED(session) LCK_MTX_ASSERT(&session->session_lock, LCK_MTX_ASSERT_OWNED)
204 
205 #define NETAGENT_LOCK_EXCLUSIVE(registration) lck_rw_lock_exclusive(&registration->agent_lock)
206 #define NETAGENT_LOCK_SHARED(registration) lck_rw_lock_shared(&registration->agent_lock)
207 #define NETAGENT_LOCK_SHARED_TO_EXCLUSIVE(registration) lck_rw_lock_shared_to_exclusive(&registration->agent_lock)
208 #define NETAGENT_UNLOCK(registration) lck_rw_done(&registration->agent_lock)
209 #define NETAGENT_ASSERT_LOCKED(registration) LCK_RW_ASSERT(&registration->agent_lock, LCK_RW_ASSERT_HELD)
210 
211 // Locking Notes
212 
213 // Precedence, where 1 is the first lock that must be taken
214 // 1. NETAGENT_LIST_LOCK - protects shared_netagent_list
215 // 2. NETAGENT_SESSION_LOCK - protects the session->registrations list
216 // 3. NETAGENT_LOCK -> protects values in a registration
217 
218 static errno_t netagent_register_control(void);
219 static errno_t netagent_ctl_connect(kern_ctl_ref kctlref, struct sockaddr_ctl *sac,
220     void **unitinfo);
221 static errno_t netagent_ctl_disconnect(kern_ctl_ref kctlref, u_int32_t unit, void *unitinfo);
222 static errno_t netagent_ctl_send(kern_ctl_ref kctlref, u_int32_t unit, void *unitinfo,
223     mbuf_t m, int flags);
224 static void netagent_ctl_rcvd(kern_ctl_ref kctlref, u_int32_t unit, void *unitinfo, int flags);
225 static errno_t netagent_ctl_getopt(kern_ctl_ref kctlref, u_int32_t unit, void *unitinfo,
226     int opt, void * __sized_by(*len)data, size_t *len);
227 static errno_t netagent_ctl_setopt(kern_ctl_ref kctlref, u_int32_t unit, void *unitinfo,
228     int opt, void * __sized_by(len)data, size_t len);
229 
230 static int netagent_send_ctl_data(u_int32_t control_unit,
231     u_int8_t *__sized_by(buffer_size)buffer, size_t buffer_size);
232 
233 static struct netagent_session *netagent_create_session(u_int32_t control_unit);
234 static void netagent_delete_session(struct netagent_session *session);
235 
236 // Register
237 static void netagent_handle_register_message(struct netagent_session *session, u_int32_t message_id,
238     size_t payload_length, mbuf_t packet, size_t offset);
239 static errno_t netagent_handle_register_setopt(struct netagent_session *session, u_int8_t *payload,
240     size_t payload_length);
241 
242 // Unregister
243 static void netagent_handle_unregister_message(struct netagent_session *session, u_int32_t message_id,
244     size_t payload_length, mbuf_t packet, size_t offset);
245 static errno_t netagent_handle_unregister_setopt(struct netagent_session *session, u_int8_t * __sized_by(payload_length)payload,
246     size_t payload_length);
247 static errno_t netagent_handle_unregister_all_setopt(struct netagent_session *session, u_int8_t * __sized_by(payload_length)payload,
248     size_t payload_length);
249 
250 // Update
251 static void netagent_handle_update_message(struct netagent_session *session, u_int32_t message_id,
252     size_t payload_length, mbuf_t packet, size_t offset);
253 static errno_t netagent_handle_update_setopt(struct netagent_session *session, u_int8_t *payload,
254     size_t payload_length);
255 
256 // Assign nexus
257 static void netagent_handle_assign_nexus_message(struct netagent_session *session, u_int32_t message_id,
258     size_t payload_length, mbuf_t packet, size_t offset);
259 static errno_t netagent_handle_assign_nexus_setopt(struct netagent_session *session, u_int8_t * __sized_by(payload_length)payload,
260     size_t payload_length);
261 
262 // Assign group
263 static errno_t netagent_handle_assign_group_setopt(struct netagent_session *session, u_int8_t * __sized_by(payload_length)payload,
264     size_t payload_length);
265 
266 // Set/get assert count
267 static errno_t netagent_handle_use_count_setopt(struct netagent_session *session, u_int8_t * __sized_by(payload_length)payload, size_t payload_length);
268 static errno_t netagent_handle_use_count_getopt(struct netagent_session *session, u_int8_t * __sized_by(*buffer_length)buffer, size_t *buffer_length);
269 
270 // Manage tokens
271 static errno_t netagent_handle_add_token_setopt(struct netagent_session *session, u_int8_t * __sized_by(token_length)token, size_t token_length);
272 static errno_t netagent_handle_flush_tokens_setopt(struct netagent_session *session, u_int8_t * __sized_by(payload_length)payload, size_t payload_length);
273 static errno_t netagent_handle_token_count_getopt(struct netagent_session *session, u_int8_t * __sized_by(*buffer_length)buffer, size_t *buffer_length);
274 static errno_t netagent_handle_token_low_water_setopt(struct netagent_session *session, u_int8_t * __sized_by(buffer_length)buffer, size_t buffer_length);
275 static errno_t netagent_handle_token_low_water_getopt(struct netagent_session *session, u_int8_t * __sized_by(*buffer_length)buffer, size_t *buffer_length);
276 
277 // Client error
278 static errno_t netagent_handle_reset_client_error_setopt(struct netagent_session *session, u_int8_t * __sized_by(payload_length)payload, size_t payload_length);
279 
280 // Enable session mode
281 static errno_t netagent_handle_enable_session_mode_setopt(struct netagent_session *session, u_int8_t *payload, size_t payload_length);
282 
283 // Requires list lock being held
284 static struct netagent_registration *netagent_find_agent_with_uuid_and_lock(uuid_t uuid, bool exclusively, bool ignore_lock);
285 
286 // Requires session lock being held
287 static struct netagent_registration *
288 netagent_session_find_agent_with_uuid_and_lock(struct netagent_session *session, uuid_t uuid, bool exclusively, bool ignore_lock);
289 
290 // Requires session lock being held, and single agent only
291 static struct netagent_registration *
292 netagent_session_access_agent_with_lock(struct netagent_session *session, bool exclusively, bool ignore_lock);
293 
294 errno_t
netagent_init(void)295 netagent_init(void)
296 {
297 	return netagent_register_control();
298 }
299 
300 static errno_t
netagent_register_control(void)301 netagent_register_control(void)
302 {
303 	struct kern_ctl_reg     kern_ctl;
304 	errno_t                 result = 0;
305 
306 	// Find a unique value for our interface family
307 	result = mbuf_tag_id_find(NETAGENT_CONTROL_NAME, &netagent_family);
308 	if (result != 0) {
309 		NETAGENTLOG(LOG_ERR, "mbuf_tag_id_find_internal failed: %d", result);
310 		return result;
311 	}
312 
313 	bzero(&kern_ctl, sizeof(kern_ctl));
314 	strlcpy(kern_ctl.ctl_name, NETAGENT_CONTROL_NAME, sizeof(kern_ctl.ctl_name));
315 	kern_ctl.ctl_name[sizeof(kern_ctl.ctl_name) - 1] = 0;
316 	kern_ctl.ctl_flags = CTL_FLAG_PRIVILEGED; // Require root
317 	kern_ctl.ctl_sendsize = 64 * 1024;
318 	kern_ctl.ctl_recvsize = 64 * 1024;
319 	kern_ctl.ctl_connect = netagent_ctl_connect;
320 	kern_ctl.ctl_disconnect = netagent_ctl_disconnect;
321 	kern_ctl.ctl_send = netagent_ctl_send;
322 	kern_ctl.ctl_rcvd = netagent_ctl_rcvd;
323 	kern_ctl.ctl_setopt = netagent_ctl_setopt;
324 	kern_ctl.ctl_getopt = netagent_ctl_getopt;
325 
326 	result = ctl_register(&kern_ctl, &netagent_kctlref);
327 	if (result != 0) {
328 		NETAGENTLOG(LOG_ERR, "ctl_register failed: %d", result);
329 		return result;
330 	}
331 
332 	return 0;
333 }
334 
335 static errno_t
netagent_ctl_connect(kern_ctl_ref kctlref,struct sockaddr_ctl * sac,void ** unitinfo)336 netagent_ctl_connect(kern_ctl_ref kctlref, struct sockaddr_ctl *sac, void **unitinfo)
337 {
338 #pragma unused(kctlref)
339 	*unitinfo = netagent_create_session(sac->sc_unit);
340 	if (*unitinfo == NULL) {
341 		// Could not allocate session
342 		return ENOBUFS;
343 	}
344 
345 	return 0;
346 }
347 
348 static errno_t
netagent_ctl_disconnect(kern_ctl_ref kctlref,u_int32_t unit,void * unitinfo)349 netagent_ctl_disconnect(kern_ctl_ref kctlref, u_int32_t unit, void *unitinfo)
350 {
351 #pragma unused(kctlref, unit)
352 	struct netagent_session *session = (struct netagent_session *)unitinfo;
353 	if (session != NULL) {
354 		netagent_delete_session(session);
355 	}
356 
357 	return 0;
358 }
359 
360 // Kernel events
361 static void
netagent_post_event(uuid_t agent_uuid,u_int32_t event_code,bool update_necp,bool should_update_immediately)362 netagent_post_event(uuid_t agent_uuid, u_int32_t event_code, bool update_necp, bool should_update_immediately)
363 {
364 	if (update_necp) {
365 		necp_update_all_clients_immediately_if_needed(should_update_immediately);
366 	}
367 
368 	struct kev_msg ev_msg;
369 	memset(&ev_msg, 0, sizeof(ev_msg));
370 
371 	struct kev_netagent_data event_data;
372 
373 	ev_msg.vendor_code      = KEV_VENDOR_APPLE;
374 	ev_msg.kev_class        = KEV_NETWORK_CLASS;
375 	ev_msg.kev_subclass     = KEV_NETAGENT_SUBCLASS;
376 	ev_msg.event_code       = event_code;
377 
378 	uuid_copy(event_data.netagent_uuid, agent_uuid);
379 	ev_msg.dv[0].data_ptr    = &event_data;
380 	ev_msg.dv[0].data_length = sizeof(event_data);
381 
382 	kev_post_msg(&ev_msg);
383 }
384 
385 // Message handling
386 static u_int8_t * __indexable
387 netagent_buffer_write_message_header(u_int8_t * __sized_by(sizeof(struct netagent_message_header) + payload_length)buffer, u_int8_t message_type, u_int8_t flags, u_int32_t message_id, u_int32_t error, size_t payload_length)
388 {
389 	memset(buffer, 0, sizeof(struct netagent_message_header));
390 	((struct netagent_message_header *)(void *)buffer)->message_type = message_type;
391 	((struct netagent_message_header *)(void *)buffer)->message_flags = flags;
392 	((struct netagent_message_header *)(void *)buffer)->message_id = message_id;
393 	((struct netagent_message_header *)(void *)buffer)->message_error = error;
394 	((struct netagent_message_header *)(void *)buffer)->message_payload_length = (u_int32_t)payload_length;
395 	return payload_length ? buffer + sizeof(struct netagent_message_header) : NULL;
396 }
397 
398 static u_int8_t * __indexable
399 netagent_buffer_write_session_message_header(u_int8_t * __sized_by(sizeof(struct netagent_session_message_header) + payload_length)buffer, u_int8_t message_type, u_int8_t flags, u_int32_t message_id, u_int32_t error, uuid_t message_agent_id, size_t payload_length)
400 {
401 	memset(buffer, 0, sizeof(struct netagent_session_message_header));
402 	((struct netagent_session_message_header *)(void *)buffer)->message_type = message_type;
403 	((struct netagent_session_message_header *)(void *)buffer)->message_flags = flags;
404 	((struct netagent_session_message_header *)(void *)buffer)->message_id = message_id;
405 	((struct netagent_session_message_header *)(void *)buffer)->message_error = error;
406 	uuid_copy(((struct netagent_session_message_header *)(void *)buffer)->message_agent_id, message_agent_id);
407 	((struct netagent_session_message_header *)(void *)buffer)->message_payload_length = (u_int32_t)payload_length;
408 	return payload_length ? buffer + sizeof(struct netagent_session_message_header) : NULL;
409 }
410 
411 static int
netagent_send_ctl_data(u_int32_t control_unit,u_int8_t * __sized_by (buffer_size)buffer,size_t buffer_size)412 netagent_send_ctl_data(u_int32_t control_unit, u_int8_t *__sized_by(buffer_size) buffer, size_t buffer_size)
413 {
414 	if (netagent_kctlref == NULL || control_unit == 0 || buffer == NULL || buffer_size == 0) {
415 		return EINVAL;
416 	}
417 
418 	return ctl_enqueuedata(netagent_kctlref, control_unit, buffer, buffer_size, CTL_DATA_EOR);
419 }
420 
421 static int
netagent_send_trigger(struct netagent_registration * registration,struct proc * p,u_int32_t flags,u_int8_t trigger_type)422 netagent_send_trigger(struct netagent_registration *registration, struct proc *p, u_int32_t flags, u_int8_t trigger_type)
423 {
424 	int error = 0;
425 	struct netagent_trigger_message *trigger_message = NULL;
426 	const bool session_mode = registration->allow_multiple_registrations;
427 	const size_t header_size = (session_mode ? sizeof(struct netagent_session_message_header) : sizeof(struct netagent_message_header));
428 	u_int8_t *trigger = NULL;
429 	size_t trigger_size = header_size + sizeof(struct netagent_trigger_message);
430 	trigger = (u_int8_t *)kalloc_data(trigger_size, Z_WAITOK);
431 	if (trigger == NULL) {
432 		return ENOMEM;
433 	}
434 
435 	if (session_mode) {
436 		(void)netagent_buffer_write_session_message_header(trigger, trigger_type, 0, 0, 0, registration->netagent->netagent_uuid, sizeof(struct netagent_trigger_message));
437 	} else {
438 		(void)netagent_buffer_write_message_header(trigger, trigger_type, 0, 0, 0, sizeof(struct netagent_trigger_message));
439 	}
440 
441 	trigger_message = (struct netagent_trigger_message *)(void *)(trigger + header_size);
442 	trigger_message->trigger_flags = flags;
443 	if (p != NULL) {
444 		trigger_message->trigger_pid = proc_pid(p);
445 		proc_getexecutableuuid(p, trigger_message->trigger_proc_uuid, sizeof(trigger_message->trigger_proc_uuid));
446 	} else {
447 		trigger_message->trigger_pid = 0;
448 		uuid_clear(trigger_message->trigger_proc_uuid);
449 	}
450 
451 	if ((error = netagent_send_ctl_data(registration->control_unit, trigger, trigger_size))) {
452 		NETAGENTLOG(LOG_ERR, "Failed to send trigger message on control unit %d", registration->control_unit);
453 	}
454 
455 	kfree_data(trigger, trigger_size);
456 	return error;
457 }
458 
459 static int
netagent_send_client_message(struct netagent_registration * registration,uuid_t client_id,u_int8_t message_type)460 netagent_send_client_message(struct netagent_registration *registration, uuid_t client_id, u_int8_t message_type)
461 {
462 	int error = 0;
463 	struct netagent_client_message *client_message = NULL;
464 	const bool session_mode = registration->allow_multiple_registrations;
465 	const size_t header_size = (session_mode ? sizeof(struct netagent_session_message_header) : sizeof(struct netagent_message_header));
466 	u_int8_t *message = NULL;
467 	size_t message_size = header_size + sizeof(struct netagent_client_message);
468 
469 	message = (u_int8_t *)kalloc_data(message_size, Z_WAITOK);
470 	if (message == NULL) {
471 		return ENOMEM;
472 	}
473 
474 	if (session_mode) {
475 		(void)netagent_buffer_write_session_message_header(message, message_type, 0, 0, 0, registration->netagent->netagent_uuid, sizeof(struct netagent_client_message));
476 	} else {
477 		(void)netagent_buffer_write_message_header(message, message_type, 0, 0, 0, sizeof(struct netagent_client_message));
478 	}
479 
480 	client_message = (struct netagent_client_message *)(void *)(message + header_size);
481 	uuid_copy(client_message->client_id, client_id);
482 
483 	if ((error = netagent_send_ctl_data(registration->control_unit, message, message_size))) {
484 		NETAGENTLOG(LOG_ERR, "Failed to send client message %d on control unit %d", message_type, registration->control_unit);
485 	}
486 
487 	kfree_data(message, message_size);
488 	return error;
489 }
490 
491 static int
netagent_send_error_message(struct netagent_registration * registration,uuid_t client_id,u_int8_t message_type,int32_t error_code)492 netagent_send_error_message(struct netagent_registration *registration, uuid_t client_id, u_int8_t message_type, int32_t error_code)
493 {
494 	int error = 0;
495 	struct netagent_client_error_message *client_message = NULL;
496 	const bool session_mode = registration->allow_multiple_registrations;
497 	const size_t header_size = (session_mode ? sizeof(struct netagent_session_message_header) : sizeof(struct netagent_message_header));
498 	u_int8_t *message = NULL;
499 	size_t message_size = header_size + sizeof(struct netagent_client_error_message);
500 
501 	message = (u_int8_t *)kalloc_data(message_size, Z_WAITOK);
502 	if (message == NULL) {
503 		return ENOMEM;
504 	}
505 
506 	if (session_mode) {
507 		(void)netagent_buffer_write_session_message_header(message, message_type, 0, 0, 0, registration->netagent->netagent_uuid, sizeof(struct netagent_client_error_message));
508 	} else {
509 		(void)netagent_buffer_write_message_header(message, message_type, 0, 0, 0, sizeof(struct netagent_client_error_message));
510 	}
511 
512 	client_message = (struct netagent_client_error_message *)(void *)(message + header_size);
513 	uuid_copy(client_message->client_id, client_id);
514 	client_message->error_code = error_code;
515 
516 	if ((error = netagent_send_ctl_data(registration->control_unit, message, message_size))) {
517 		NETAGENTLOG(LOG_ERR, "Failed to send client message %d on control unit %d", message_type, registration->control_unit);
518 	}
519 
520 	kfree_data(message, message_size);
521 	return error;
522 }
523 
524 static int
netagent_send_group_message(struct netagent_registration * registration,uuid_t client_id,u_int8_t message_type,struct necp_client_group_members * group_members)525 netagent_send_group_message(struct netagent_registration *registration, uuid_t client_id, u_int8_t message_type, struct necp_client_group_members *group_members)
526 {
527 	int error = 0;
528 	struct netagent_client_group_message * __single client_message = NULL;
529 	const bool session_mode = registration->allow_multiple_registrations;
530 	const size_t header_size = (session_mode ? sizeof(struct netagent_session_message_header) : sizeof(struct netagent_message_header));
531 	u_int8_t *message = NULL;
532 	size_t message_size = header_size + sizeof(struct netagent_client_group_message) + group_members->group_members_length;
533 
534 	message = (u_int8_t *)kalloc_data(message_size, Z_WAITOK);
535 	if (message == NULL) {
536 		return ENOMEM;
537 	}
538 
539 	if (session_mode) {
540 		(void)netagent_buffer_write_session_message_header(message, message_type, 0, 0, 0, registration->netagent->netagent_uuid, sizeof(struct netagent_client_group_message) + group_members->group_members_length);
541 	} else {
542 		(void)netagent_buffer_write_message_header(message, message_type, 0, 0, 0, sizeof(struct netagent_client_group_message) + group_members->group_members_length);
543 	}
544 
545 	client_message = (struct netagent_client_group_message *)(void *)(message + header_size);
546 	uuid_copy(client_message->client_id, client_id);
547 	memcpy(netagent_group_message_get_members(client_message, group_members->group_members_length), group_members->group_members, group_members->group_members_length);
548 
549 	if ((error = netagent_send_ctl_data(registration->control_unit, message, message_size))) {
550 		NETAGENTLOG(LOG_ERR, "Failed to send client group message %d on control unit %d", message_type, registration->control_unit);
551 	}
552 
553 	kfree_data(message, message_size);
554 	return error;
555 }
556 
557 static int
netagent_send_tokens_needed(struct netagent_registration * registration)558 netagent_send_tokens_needed(struct netagent_registration *registration)
559 {
560 	const u_int8_t message_type = NETAGENT_MESSAGE_TYPE_TOKENS_NEEDED;
561 	int error = 0;
562 	u_int8_t *message = NULL;
563 	const bool session_mode = registration->allow_multiple_registrations;
564 	const size_t header_size = (session_mode ? sizeof(struct netagent_session_message_header) : sizeof(struct netagent_message_header));
565 	size_t message_size = header_size;
566 
567 	message = (u_int8_t *)kalloc_data(message_size, Z_WAITOK);
568 	if (message == NULL) {
569 		return ENOMEM;
570 	}
571 
572 	if (session_mode) {
573 		(void)netagent_buffer_write_session_message_header(message, message_type, 0, 0, 0, registration->netagent->netagent_uuid, 0);
574 	} else {
575 		(void)netagent_buffer_write_message_header(message, message_type, 0, 0, 0, 0);
576 	}
577 
578 	if ((error = netagent_send_ctl_data(registration->control_unit, message, message_size))) {
579 		NETAGENTLOG(LOG_ERR, "Failed to send client tokens needed message on control unit %d", registration->control_unit);
580 	}
581 
582 	kfree_data(message, message_size);
583 	return error;
584 }
585 
586 static int
netagent_send_success_response(struct netagent_session * session,u_int8_t message_type,u_int32_t message_id)587 netagent_send_success_response(struct netagent_session *session, u_int8_t message_type, u_int32_t message_id)
588 {
589 	int error = 0;
590 	u_int8_t *response = NULL;
591 	size_t response_size = sizeof(struct netagent_message_header);
592 
593 	response = (u_int8_t *)kalloc_data(response_size, Z_WAITOK);
594 	if (response == NULL) {
595 		return ENOMEM;
596 	}
597 	(void)netagent_buffer_write_message_header(response, message_type, NETAGENT_MESSAGE_FLAGS_RESPONSE, message_id, 0, 0);
598 
599 	if ((error = netagent_send_ctl_data(session->control_unit, response, response_size))) {
600 		NETAGENTLOG0(LOG_ERR, "Failed to send response");
601 	}
602 
603 	kfree_data(response, response_size);
604 	return error;
605 }
606 
607 static errno_t
netagent_send_error_response(struct netagent_session * session,u_int8_t message_type,u_int32_t message_id,u_int32_t error_code)608 netagent_send_error_response(struct netagent_session *session, u_int8_t message_type,
609     u_int32_t message_id, u_int32_t error_code)
610 {
611 	int error = 0;
612 	u_int8_t *response = NULL;
613 	size_t response_size = sizeof(struct netagent_message_header);
614 
615 	if (session == NULL) {
616 		NETAGENTLOG0(LOG_ERR, "Got a NULL session");
617 		return EINVAL;
618 	}
619 
620 	response = (u_int8_t *)kalloc_data(response_size, Z_WAITOK);
621 	if (response == NULL) {
622 		return ENOMEM;
623 	}
624 	(void)netagent_buffer_write_message_header(response, message_type, NETAGENT_MESSAGE_FLAGS_RESPONSE,
625 	    message_id, error_code, 0);
626 
627 	if ((error = netagent_send_ctl_data(session->control_unit, response, response_size))) {
628 		NETAGENTLOG0(LOG_ERR, "Failed to send response");
629 	}
630 
631 	kfree_data(response, response_size);
632 	return error;
633 }
634 
635 static errno_t
netagent_ctl_send(kern_ctl_ref kctlref,u_int32_t unit,void * unitinfo,mbuf_t packet,int flags)636 netagent_ctl_send(kern_ctl_ref kctlref, u_int32_t unit, void *unitinfo, mbuf_t packet, int flags)
637 {
638 #pragma unused(kctlref, unit, flags)
639 	struct netagent_session *session = (struct netagent_session *)unitinfo;
640 	struct netagent_message_header header;
641 	int error = 0;
642 
643 	if (session == NULL) {
644 		NETAGENTLOG0(LOG_ERR, "Got a NULL session");
645 		error = EINVAL;
646 		goto done;
647 	}
648 
649 	if (mbuf_pkthdr_len(packet) < sizeof(header)) {
650 		NETAGENTLOG(LOG_ERR, "Got a bad packet, length (%lu) < sizeof header (%lu)",
651 		    mbuf_pkthdr_len(packet), sizeof(header));
652 		error = EINVAL;
653 		goto done;
654 	}
655 
656 	error = mbuf_copydata(packet, 0, sizeof(header), &header);
657 	if (error) {
658 		NETAGENTLOG(LOG_ERR, "mbuf_copydata failed for the header: %d", error);
659 		error = ENOBUFS;
660 		goto done;
661 	}
662 
663 	switch (header.message_type) {
664 	case NETAGENT_MESSAGE_TYPE_REGISTER: {
665 		netagent_handle_register_message(session, header.message_id, header.message_payload_length,
666 		    packet, sizeof(header));
667 		break;
668 	}
669 	case NETAGENT_MESSAGE_TYPE_UNREGISTER: {
670 		netagent_handle_unregister_message(session, header.message_id, header.message_payload_length,
671 		    packet, sizeof(header));
672 		break;
673 	}
674 	case NETAGENT_MESSAGE_TYPE_UPDATE: {
675 		netagent_handle_update_message(session, header.message_id, header.message_payload_length,
676 		    packet, sizeof(header));
677 		break;
678 	}
679 	case NETAGENT_MESSAGE_TYPE_GET: {
680 		NETAGENTLOG0(LOG_ERR, "NETAGENT_MESSAGE_TYPE_GET no longer supported");
681 		break;
682 	}
683 	case NETAGENT_MESSAGE_TYPE_ASSERT: {
684 		NETAGENTLOG0(LOG_ERR, "NETAGENT_MESSAGE_TYPE_ASSERT no longer supported");
685 		break;
686 	}
687 	case NETAGENT_MESSAGE_TYPE_UNASSERT: {
688 		NETAGENTLOG0(LOG_ERR, "NETAGENT_MESSAGE_TYPE_UNASSERT no longer supported");
689 		break;
690 	}
691 	case NETAGENT_MESSAGE_TYPE_ASSIGN_NEXUS: {
692 		netagent_handle_assign_nexus_message(session, header.message_id, header.message_payload_length,
693 		    packet, sizeof(header));
694 		break;
695 	}
696 	default: {
697 		NETAGENTLOG(LOG_ERR, "Received unknown message type %d", header.message_type);
698 		netagent_send_error_response(session, header.message_type, header.message_id,
699 		    NETAGENT_MESSAGE_ERROR_UNKNOWN_TYPE);
700 		break;
701 	}
702 	}
703 
704 done:
705 	mbuf_freem(packet);
706 	return error;
707 }
708 
709 static void
netagent_ctl_rcvd(kern_ctl_ref kctlref,u_int32_t unit,void * unitinfo,int flags)710 netagent_ctl_rcvd(kern_ctl_ref kctlref, u_int32_t unit, void *unitinfo, int flags)
711 {
712 #pragma unused(kctlref, unit, unitinfo, flags)
713 	return;
714 }
715 
716 static errno_t
netagent_ctl_getopt(kern_ctl_ref kctlref,u_int32_t unit,void * unitinfo,int opt,void * __sized_by (* len)data,size_t * len)717 netagent_ctl_getopt(kern_ctl_ref kctlref, u_int32_t unit, void *unitinfo, int opt,
718     void * __sized_by(*len)data, size_t *len)
719 {
720 #pragma unused(kctlref, unit)
721 	struct netagent_session *session = (struct netagent_session *)unitinfo;
722 	errno_t error;
723 
724 	if (session == NULL) {
725 		NETAGENTLOG0(LOG_ERR, "Received a NULL session");
726 		error = EINVAL;
727 		goto done;
728 	}
729 
730 	switch (opt) {
731 	case NETAGENT_OPTION_TYPE_USE_COUNT: {
732 		NETAGENTLOG0(LOG_DEBUG, "Request to get use count");
733 		error = netagent_handle_use_count_getopt(session, data, len);
734 		break;
735 	}
736 	case NETAGENT_OPTION_TYPE_TOKEN_COUNT: {
737 		NETAGENTLOG0(LOG_DEBUG, "Request to get token count");
738 		error = netagent_handle_token_count_getopt(session, data, len);
739 		break;
740 	}
741 	case NETAGENT_OPTION_TYPE_TOKEN_LOW_WATER: {
742 		NETAGENTLOG0(LOG_DEBUG, "Request to get token low water mark");
743 		error = netagent_handle_token_low_water_getopt(session, data, len);
744 		break;
745 	}
746 	default:
747 		NETAGENTLOG0(LOG_ERR, "Received unknown option");
748 		error = ENOPROTOOPT;
749 		break;
750 	}
751 
752 done:
753 	return error;
754 }
755 
756 static errno_t
netagent_ctl_setopt(kern_ctl_ref kctlref,u_int32_t unit,void * unitinfo,int opt,void * __sized_by (len)data,size_t len)757 netagent_ctl_setopt(kern_ctl_ref kctlref, u_int32_t unit, void *unitinfo, int opt,
758     void * __sized_by(len)data, size_t len)
759 {
760 #pragma unused(kctlref, unit)
761 	struct netagent_session *session = (struct netagent_session *)unitinfo;
762 	errno_t error;
763 
764 	if (session == NULL) {
765 		NETAGENTLOG0(LOG_ERR, "Received a NULL session");
766 		error = EINVAL;
767 		goto done;
768 	}
769 
770 	switch (opt) {
771 	case NETAGENT_OPTION_TYPE_REGISTER: {
772 		NETAGENTLOG0(LOG_DEBUG, "Request for registration");
773 		error = netagent_handle_register_setopt(session, data, len);
774 		break;
775 	}
776 	case NETAGENT_OPTION_TYPE_UPDATE: {
777 		NETAGENTLOG0(LOG_DEBUG, "Request for update");
778 		error = netagent_handle_update_setopt(session, data, len);
779 		break;
780 	}
781 	case NETAGENT_OPTION_TYPE_UNREGISTER: {
782 		NETAGENTLOG0(LOG_DEBUG, "Request for unregistration");
783 		error = netagent_handle_unregister_setopt(session, data, len);
784 		break;
785 	}
786 	case NETAGENT_OPTION_TYPE_ASSIGN_NEXUS: {
787 		NETAGENTLOG0(LOG_DEBUG, "Request for assigning nexus");
788 		error = netagent_handle_assign_nexus_setopt(session, data, len);
789 		break;
790 	}
791 	case NETAGENT_MESSAGE_TYPE_ASSIGN_GROUP_MEMBERS: {
792 		NETAGENTLOG0(LOG_DEBUG, "Request for assigning group members");
793 		error = netagent_handle_assign_group_setopt(session, data, len);
794 		break;
795 	}
796 	case NETAGENT_OPTION_TYPE_USE_COUNT: {
797 		NETAGENTLOG0(LOG_DEBUG, "Request to set use count");
798 		error = netagent_handle_use_count_setopt(session, data, len);
799 		break;
800 	}
801 	case NETAGENT_OPTION_TYPE_ADD_TOKEN: {
802 		NETAGENTLOG0(LOG_DEBUG, "Request to add a token");
803 		error = netagent_handle_add_token_setopt(session, data, len);
804 		break;
805 	}
806 	case NETAGENT_OPTION_TYPE_FLUSH_TOKENS: {
807 		NETAGENTLOG0(LOG_DEBUG, "Request to flush tokens");
808 		error = netagent_handle_flush_tokens_setopt(session, data, len);
809 		break;
810 	}
811 	case NETAGENT_OPTION_TYPE_TOKEN_LOW_WATER: {
812 		NETAGENTLOG0(LOG_DEBUG, "Request to set token low water mark");
813 		error = netagent_handle_token_low_water_setopt(session, data, len);
814 		break;
815 	}
816 	case NETAGENT_OPTION_TYPE_RESET_CLIENT_ERROR: {
817 		NETAGENTLOG0(LOG_DEBUG, "Request to reset client error");
818 		error = netagent_handle_reset_client_error_setopt(session, data, len);
819 		break;
820 	}
821 	case NETAGENT_OPTION_TYPE_ENABLE_SESSION_MODE: {
822 		NETAGENTLOG0(LOG_DEBUG, "Request to enable session mode");
823 		error = netagent_handle_enable_session_mode_setopt(session, data, len);
824 		break;
825 	}
826 	case NETAGENT_OPTION_TYPE_UNREGISTER_ALL: {
827 		NETAGENTLOG0(LOG_DEBUG, "Request for unregistration of all agents");
828 		error = netagent_handle_unregister_all_setopt(session, data, len);
829 		break;
830 	}
831 	default:
832 		NETAGENTLOG0(LOG_ERR, "Received unknown option");
833 		error = ENOPROTOOPT;
834 		break;
835 	}
836 
837 done:
838 	return error;
839 }
840 
841 // Session Management
842 static struct netagent_session *
netagent_create_session(u_int32_t control_unit)843 netagent_create_session(u_int32_t control_unit)
844 {
845 	struct netagent_session *new_session = NULL;
846 
847 	new_session = kalloc_type(struct netagent_session,
848 	    Z_WAITOK | Z_ZERO | Z_NOFAIL);
849 	NETAGENTLOG(LOG_DEBUG, "Create agent session, control unit %d", control_unit);
850 	new_session->control_unit = control_unit;
851 	lck_mtx_init(&new_session->session_lock, &netagent_mtx_grp, LCK_ATTR_NULL);
852 	TAILQ_INIT(&new_session->registrations);
853 
854 	return new_session;
855 }
856 
857 netagent_session_t
netagent_create(netagent_event_f event_handler,void * context)858 netagent_create(netagent_event_f event_handler, void *context)
859 {
860 	struct netagent_session *session = netagent_create_session(0);
861 	if (session == NULL) {
862 		return NULL;
863 	}
864 
865 	session->event_handler = event_handler;
866 	session->event_context = context;
867 	return session;
868 }
869 
870 static void
netagent_token_free(struct netagent_token * token)871 netagent_token_free(struct netagent_token *token)
872 {
873 	kfree_data(token->token_bytes, token->token_length);
874 	kfree_type(struct netagent_token, token);
875 }
876 
877 static struct netagent_registration *
netagent_alloc_registration_memory(uint32_t data_size)878 netagent_alloc_registration_memory(uint32_t data_size)
879 {
880 	struct netagent_registration *new_registration;
881 	size_t netagent_alloc_size = sizeof(struct netagent) + data_size;
882 
883 	new_registration = kalloc_type(struct netagent_registration,
884 	    Z_WAITOK | Z_ZERO | Z_NOFAIL);
885 	new_registration->netagent = kalloc_data(netagent_alloc_size, Z_WAITOK | Z_NOFAIL);
886 	new_registration->netagent_alloc_size = netagent_alloc_size;
887 
888 	lck_rw_init(&new_registration->agent_lock, &netagent_mtx_grp, LCK_ATTR_NULL);
889 
890 	return new_registration;
891 }
892 
893 static void
netagent_free_registration_memory(struct netagent_registration * registration)894 netagent_free_registration_memory(struct netagent_registration *registration)
895 {
896 	// Before destroying the lock, take the lock exclusively and then
897 	// drop it again. This ensures that no other thread was holding
898 	// onto the lock at the time of destroying it.
899 	// This can happen in netagent_client_message_with_params due
900 	// to the fact that the registration lock needs to be held during the
901 	// event callout, while the list lock has been released. Taking
902 	// this lock here ensures that any such remaining thread completes
903 	// before this object is released. Since the registration object has
904 	// already been removed from any and all lists by this point,
905 	// there isn't any way for a new thread to start referencing it.
906 	NETAGENT_LOCK_EXCLUSIVE(registration);
907 	NETAGENT_UNLOCK(registration);
908 	lck_rw_destroy(&registration->agent_lock, &netagent_mtx_grp);
909 
910 	kfree_data_sized_by(registration->netagent, registration->netagent_alloc_size);
911 	kfree_type(struct netagent_registration, registration);
912 }
913 
914 static void
netagent_free_registration(struct netagent_registration * registration)915 netagent_free_registration(struct netagent_registration *registration)
916 {
917 	// Free any leftover tokens
918 	struct netagent_token *search_token = NULL;
919 	struct netagent_token *temp_token = NULL;
920 	TAILQ_FOREACH_SAFE(search_token, &registration->token_list, token_chain, temp_token) {
921 		TAILQ_REMOVE(&registration->token_list, search_token, token_chain);
922 		netagent_token_free(search_token);
923 	}
924 
925 	// Free any pending client triggers
926 	struct netagent_client * __single search_client = NULL;
927 	struct netagent_client *temp_client = NULL;
928 	LIST_FOREACH_SAFE(search_client, &registration->pending_triggers_list, client_chain, temp_client) {
929 		LIST_REMOVE(search_client, client_chain);
930 		kfree_type(struct netagent_client, search_client);
931 	}
932 
933 	// Free registration itself
934 	netagent_free_registration_memory(registration);
935 }
936 
937 static void
netagent_unregister_all_session_registrations(struct netagent_session * session)938 netagent_unregister_all_session_registrations(struct netagent_session *session)
939 {
940 	TAILQ_HEAD(_netagent_registration_list, netagent_registration) deleting_registrations;
941 	TAILQ_INIT(&deleting_registrations);
942 	NETAGENT_LIST_LOCK_EXCLUSIVE();
943 	if (session != NULL) {
944 		NETAGENT_SESSION_LOCK(session);
945 		struct netagent_registration *registration = NULL;
946 		struct netagent_registration *temp_registration = NULL;
947 		TAILQ_FOREACH_SAFE(registration, &session->registrations, session_chain, temp_registration) {
948 			if (netagent_registered_count > 0) {
949 				netagent_registered_count--;
950 			}
951 			if ((registration->netagent->netagent_flags & NETAGENT_FLAG_ACTIVE) &&
952 			    netagent_active_count > 0) {
953 				netagent_active_count--;
954 			}
955 
956 			LIST_REMOVE(registration, global_chain);
957 			TAILQ_REMOVE(&session->registrations, registration, session_chain);
958 			TAILQ_INSERT_TAIL(&deleting_registrations, registration, session_chain);
959 			NETAGENTLOG0(LOG_DEBUG, "Unregistered agent");
960 		}
961 		NETAGENT_SESSION_UNLOCK(session);
962 	}
963 	NETAGENT_LIST_UNLOCK();
964 
965 	struct netagent_registration *registration = NULL;
966 	struct netagent_registration *temp_registration = NULL;
967 	TAILQ_FOREACH_SAFE(registration, &deleting_registrations, session_chain, temp_registration) {
968 		TAILQ_REMOVE(&deleting_registrations, registration, session_chain);
969 
970 		ifnet_clear_netagent(registration->netagent->netagent_uuid);
971 		netagent_post_event(registration->netagent->netagent_uuid, KEV_NETAGENT_UNREGISTERED, TRUE, false);
972 
973 		netagent_free_registration(registration);
974 	}
975 }
976 
977 static void
netagent_unregister_one_session_registration(struct netagent_session * session,uuid_t agent_id)978 netagent_unregister_one_session_registration(struct netagent_session *session, uuid_t agent_id)
979 {
980 	bool unregistered = false;
981 	NETAGENT_LIST_LOCK_EXCLUSIVE();
982 	if (session != NULL) {
983 		NETAGENT_SESSION_LOCK(session);
984 		struct netagent_registration *registration = NULL;
985 		struct netagent_registration *temp_registration = NULL;
986 		TAILQ_FOREACH_SAFE(registration, &session->registrations, session_chain, temp_registration) {
987 			if (uuid_compare(agent_id, registration->netagent->netagent_uuid) != 0) {
988 				// Not a match, skip
989 				continue;
990 			}
991 
992 			if (netagent_registered_count > 0) {
993 				netagent_registered_count--;
994 			}
995 			if ((registration->netagent->netagent_flags & NETAGENT_FLAG_ACTIVE) &&
996 			    netagent_active_count > 0) {
997 				netagent_active_count--;
998 			}
999 
1000 			LIST_REMOVE(registration, global_chain);
1001 			TAILQ_REMOVE(&session->registrations, registration, session_chain);
1002 
1003 			unregistered = true;
1004 			netagent_free_registration(registration);
1005 
1006 			NETAGENTLOG0(LOG_DEBUG, "Unregistered agent");
1007 		}
1008 		NETAGENT_SESSION_UNLOCK(session);
1009 	}
1010 	NETAGENT_LIST_UNLOCK();
1011 
1012 	if (unregistered) {
1013 		ifnet_clear_netagent(agent_id);
1014 		netagent_post_event(agent_id, KEV_NETAGENT_UNREGISTERED, TRUE, false);
1015 	}
1016 }
1017 
1018 static void
netagent_delete_session(struct netagent_session * session)1019 netagent_delete_session(struct netagent_session *session)
1020 {
1021 	if (session != NULL) {
1022 		netagent_unregister_all_session_registrations(session);
1023 		lck_mtx_destroy(&session->session_lock, &netagent_mtx_grp);
1024 		kfree_type(struct netagent_session, session);
1025 	}
1026 }
1027 
1028 void
netagent_destroy(netagent_session_t session)1029 netagent_destroy(netagent_session_t session)
1030 {
1031 	return netagent_delete_session((struct netagent_session *)session);
1032 }
1033 
1034 static size_t
netagent_packet_get_netagent_data_size(mbuf_t packet,size_t offset,int * err)1035 netagent_packet_get_netagent_data_size(mbuf_t packet, size_t offset, int *err)
1036 {
1037 	int error = 0;
1038 
1039 	struct netagent netagent_peek;
1040 	memset(&netagent_peek, 0, sizeof(netagent_peek));
1041 
1042 	*err = 0;
1043 
1044 	error = mbuf_copydata(packet, offset, sizeof(netagent_peek), &netagent_peek);
1045 	if (error) {
1046 		*err = ENOENT;
1047 		return 0;
1048 	}
1049 
1050 	return netagent_peek.netagent_data_size;
1051 }
1052 
1053 static errno_t
netagent_handle_register_inner(struct netagent_session * session,struct netagent_registration * new_registration)1054 netagent_handle_register_inner(struct netagent_session *session, struct netagent_registration *new_registration)
1055 {
1056 	NETAGENT_LIST_LOCK_EXCLUSIVE();
1057 
1058 	NETAGENT_SESSION_LOCK(session);
1059 
1060 	if (!session->allow_multiple_registrations && !TAILQ_EMPTY(&session->registrations)) {
1061 		NETAGENT_SESSION_UNLOCK(session);
1062 		NETAGENT_LIST_UNLOCK();
1063 		return EINVAL;
1064 	}
1065 
1066 	struct netagent_registration *existing_registration = netagent_find_agent_with_uuid_and_lock(new_registration->netagent->netagent_uuid, false, true);
1067 	if (existing_registration != NULL) {
1068 		NETAGENTLOG0(LOG_ERR, "Existing agent registration UUID conflicts with new agent registration");
1069 		NETAGENT_SESSION_UNLOCK(session);
1070 		NETAGENT_LIST_UNLOCK();
1071 		return EEXIST;
1072 	}
1073 
1074 	new_registration->control_unit = session->control_unit;
1075 	new_registration->allow_multiple_registrations = session->allow_multiple_registrations;
1076 	new_registration->event_handler = session->event_handler;
1077 	new_registration->event_context = session->event_context;
1078 	new_registration->generation = g_next_generation++;
1079 
1080 	TAILQ_INSERT_TAIL(&session->registrations, new_registration, session_chain);
1081 	LIST_INSERT_HEAD(&shared_netagent_list, new_registration, global_chain);
1082 	TAILQ_INIT(&new_registration->token_list);
1083 	LIST_INIT(&new_registration->pending_triggers_list);
1084 
1085 	new_registration->netagent->netagent_flags |= NETAGENT_FLAG_REGISTERED;
1086 	netagent_registered_count++;
1087 	if (new_registration->netagent->netagent_flags & NETAGENT_FLAG_ACTIVE) {
1088 		netagent_active_count++;
1089 	}
1090 
1091 	NETAGENT_SESSION_UNLOCK(session);
1092 	NETAGENT_LIST_UNLOCK();
1093 	return 0;
1094 }
1095 
1096 errno_t
netagent_register(netagent_session_t _session,struct netagent * agent)1097 netagent_register(netagent_session_t _session, struct netagent *agent)
1098 {
1099 	struct netagent_registration *new_registration = NULL;
1100 	uuid_t registered_uuid;
1101 
1102 	struct netagent_session *session = (struct netagent_session *)_session;
1103 	if (session == NULL) {
1104 		NETAGENTLOG0(LOG_ERR, "Cannot register agent on NULL session");
1105 		return EINVAL;
1106 	}
1107 
1108 	if (agent == NULL) {
1109 		NETAGENTLOG0(LOG_ERR, "Cannot register NULL agent");
1110 		return EINVAL;
1111 	}
1112 
1113 	size_t data_size = agent->netagent_data_size;
1114 	if (data_size > NETAGENT_MAX_DATA_SIZE) {
1115 		NETAGENTLOG(LOG_ERR, "Register message size could not be read, data_size %zu",
1116 		    data_size);
1117 		return EINVAL;
1118 	}
1119 
1120 	new_registration = netagent_alloc_registration_memory(data_size);
1121 
1122 	__nochk_memcpy(new_registration->netagent, agent, sizeof(struct netagent));
1123 	__nochk_memcpy(netagent_get_data(new_registration->netagent), netagent_get_data(agent), data_size);
1124 
1125 	uuid_copy(registered_uuid, new_registration->netagent->netagent_uuid);
1126 
1127 	errno_t error = netagent_handle_register_inner(session, new_registration);
1128 	if (error != 0) {
1129 		netagent_free_registration_memory(new_registration);
1130 		return error;
1131 	}
1132 
1133 	NETAGENTLOG0(LOG_DEBUG, "Registered new agent");
1134 	netagent_post_event(registered_uuid, KEV_NETAGENT_REGISTERED, TRUE, false);
1135 
1136 	return 0;
1137 }
1138 
1139 static errno_t
netagent_handle_register_setopt(struct netagent_session * session,u_int8_t * payload,size_t payload_length)1140 netagent_handle_register_setopt(struct netagent_session *session, u_int8_t *payload,
1141     size_t payload_length)
1142 {
1143 	struct netagent_registration *new_registration = NULL;
1144 	errno_t response_error = 0;
1145 	struct netagent *register_netagent = (struct netagent *)(void *)payload;
1146 	uuid_t registered_uuid;
1147 
1148 	if (session == NULL) {
1149 		NETAGENTLOG0(LOG_ERR, "Failed to find session");
1150 		response_error = EINVAL;
1151 		goto done;
1152 	}
1153 
1154 	if (payload == NULL) {
1155 		NETAGENTLOG0(LOG_ERR, "No payload received");
1156 		response_error = EINVAL;
1157 		goto done;
1158 	}
1159 
1160 	if (payload_length < sizeof(struct netagent)) {
1161 		NETAGENTLOG(LOG_ERR, "Register message size too small for agent: (%zu < %zu)",
1162 		    payload_length, sizeof(struct netagent));
1163 		response_error = EINVAL;
1164 		goto done;
1165 	}
1166 
1167 	size_t data_size = register_netagent->netagent_data_size;
1168 	if (data_size > NETAGENT_MAX_DATA_SIZE) {
1169 		NETAGENTLOG(LOG_ERR, "Register message size could not be read, data_size %zu", data_size);
1170 		response_error = EINVAL;
1171 		goto done;
1172 	}
1173 
1174 	if (payload_length != (sizeof(struct netagent) + data_size)) {
1175 		NETAGENTLOG(LOG_ERR, "Mismatch between data size and payload length (%lu != %zu)", (sizeof(struct netagent) + data_size), payload_length);
1176 		response_error = EINVAL;
1177 		goto done;
1178 	}
1179 
1180 	new_registration = netagent_alloc_registration_memory(data_size);
1181 
1182 	__nochk_memcpy(new_registration->netagent, register_netagent, sizeof(struct netagent));
1183 	__nochk_memcpy(netagent_get_data(new_registration->netagent), netagent_get_data(register_netagent), data_size);
1184 
1185 	uuid_copy(registered_uuid, new_registration->netagent->netagent_uuid);
1186 
1187 	response_error = netagent_handle_register_inner(session, new_registration);
1188 	if (response_error != 0) {
1189 		netagent_free_registration_memory(new_registration);
1190 		goto done;
1191 	}
1192 
1193 	NETAGENTLOG0(LOG_DEBUG, "Registered new agent");
1194 	netagent_post_event(registered_uuid, KEV_NETAGENT_REGISTERED, TRUE, false);
1195 
1196 done:
1197 	return response_error;
1198 }
1199 
1200 static void
netagent_handle_register_message(struct netagent_session * session,u_int32_t message_id,size_t payload_length,mbuf_t packet,size_t offset)1201 netagent_handle_register_message(struct netagent_session *session, u_int32_t message_id,
1202     size_t payload_length, mbuf_t packet, size_t offset)
1203 {
1204 	errno_t error;
1205 	struct netagent_registration *new_registration = NULL;
1206 	u_int32_t response_error = NETAGENT_MESSAGE_ERROR_INTERNAL;
1207 	uuid_t registered_uuid;
1208 
1209 	if (session == NULL) {
1210 		NETAGENTLOG0(LOG_ERR, "Failed to find session");
1211 		response_error = NETAGENT_MESSAGE_ERROR_INTERNAL;
1212 		goto fail;
1213 	}
1214 
1215 	if (session->allow_multiple_registrations) {
1216 		NETAGENTLOG0(LOG_ERR, "Not allowed to register multiple agents");
1217 		response_error = NETAGENT_MESSAGE_ERROR_INVALID_DATA;
1218 		goto fail;
1219 	}
1220 
1221 	if (payload_length < sizeof(struct netagent)) {
1222 		NETAGENTLOG(LOG_ERR, "Register message size too small for agent: (%zu < %zu)",
1223 		    payload_length, sizeof(struct netagent));
1224 		response_error = NETAGENT_MESSAGE_ERROR_INVALID_DATA;
1225 		goto fail;
1226 	}
1227 
1228 	size_t data_size = netagent_packet_get_netagent_data_size(packet, offset, &error);
1229 	if (error || data_size > NETAGENT_MAX_DATA_SIZE) {
1230 		NETAGENTLOG(LOG_ERR, "Register message size could not be read, error %d data_size %zu",
1231 		    error, data_size);
1232 		response_error = NETAGENT_MESSAGE_ERROR_INVALID_DATA;
1233 		goto fail;
1234 	}
1235 
1236 	new_registration = netagent_alloc_registration_memory(data_size);
1237 
1238 	error = mbuf_copydata(packet, offset, sizeof(struct netagent) + data_size,
1239 	    new_registration->netagent);
1240 	if (error) {
1241 		NETAGENTLOG(LOG_ERR, "Failed to read data into agent structure: %d", error);
1242 		netagent_free_registration_memory(new_registration);
1243 		response_error = NETAGENT_MESSAGE_ERROR_INTERNAL;
1244 		goto fail;
1245 	}
1246 
1247 	uuid_copy(registered_uuid, new_registration->netagent->netagent_uuid);
1248 
1249 	error = netagent_handle_register_inner(session, new_registration);
1250 	if (error) {
1251 		NETAGENTLOG(LOG_ERR, "Failed to register agent: %d", error);
1252 		netagent_free_registration_memory(new_registration);
1253 		response_error = NETAGENT_MESSAGE_ERROR_INTERNAL;
1254 		goto fail;
1255 	}
1256 
1257 	NETAGENTLOG0(LOG_DEBUG, "Registered new agent");
1258 	netagent_send_success_response(session, NETAGENT_MESSAGE_TYPE_REGISTER, message_id);
1259 	netagent_post_event(registered_uuid, KEV_NETAGENT_REGISTERED, TRUE, false);
1260 	return;
1261 fail:
1262 	netagent_send_error_response(session, NETAGENT_MESSAGE_TYPE_REGISTER, message_id, response_error);
1263 }
1264 
1265 errno_t
netagent_unregister(netagent_session_t _session)1266 netagent_unregister(netagent_session_t _session)
1267 {
1268 	struct netagent_session *session = (struct netagent_session *)_session;
1269 	if (session == NULL) {
1270 		NETAGENTLOG0(LOG_ERR, "Cannot unregister NULL session");
1271 		return EINVAL;
1272 	}
1273 
1274 	netagent_unregister_all_session_registrations(session);
1275 	return 0;
1276 }
1277 
1278 static errno_t
netagent_handle_unregister_setopt(struct netagent_session * session,u_int8_t * __sized_by (payload_length)payload,size_t payload_length)1279 netagent_handle_unregister_setopt(struct netagent_session *session, u_int8_t * __sized_by(payload_length) payload,
1280     size_t payload_length)
1281 {
1282 	errno_t response_error = 0;
1283 
1284 	if (session == NULL) {
1285 		NETAGENTLOG0(LOG_ERR, "Failed to find session");
1286 		response_error = EINVAL;
1287 		goto done;
1288 	}
1289 
1290 	if (!session->allow_multiple_registrations) {
1291 		netagent_unregister_all_session_registrations(session);
1292 	} else {
1293 		if (payload == NULL) {
1294 			NETAGENTLOG0(LOG_ERR, "No payload received");
1295 			response_error = EINVAL;
1296 			goto done;
1297 		}
1298 
1299 		if (payload_length < sizeof(uuid_t)) {
1300 			NETAGENTLOG(LOG_ERR, "Unregister message size too small for UUID: (%zu < %zu)",
1301 			    payload_length, sizeof(uuid_t));
1302 			response_error = EINVAL;
1303 			goto done;
1304 		}
1305 
1306 		uuid_t agent_uuid = {};
1307 		uuid_copy(agent_uuid, payload);
1308 		netagent_unregister_one_session_registration(session, agent_uuid);
1309 	}
1310 
1311 done:
1312 	return response_error;
1313 }
1314 
1315 static errno_t
netagent_handle_unregister_all_setopt(struct netagent_session * session,u_int8_t * __sized_by (payload_length)payload,size_t payload_length)1316 netagent_handle_unregister_all_setopt(struct netagent_session *session, u_int8_t * __sized_by(payload_length) payload,
1317     size_t payload_length)
1318 {
1319 #pragma unused(payload, payload_length)
1320 
1321 	errno_t response_error = 0;
1322 
1323 	if (session == NULL) {
1324 		NETAGENTLOG0(LOG_ERR, "Failed to find session");
1325 		response_error = EINVAL;
1326 		goto done;
1327 	}
1328 
1329 	netagent_unregister_all_session_registrations(session);
1330 
1331 done:
1332 	return response_error;
1333 }
1334 
1335 static void
netagent_handle_unregister_message(struct netagent_session * session,u_int32_t message_id,size_t payload_length,mbuf_t packet,size_t offset)1336 netagent_handle_unregister_message(struct netagent_session *session, u_int32_t message_id,
1337     size_t payload_length, mbuf_t packet, size_t offset)
1338 {
1339 #pragma unused(payload_length, packet, offset)
1340 	u_int32_t response_error = NETAGENT_MESSAGE_ERROR_INTERNAL;
1341 
1342 	if (session == NULL) {
1343 		NETAGENTLOG0(LOG_ERR, "Failed to find session");
1344 		response_error = NETAGENT_MESSAGE_ERROR_INTERNAL;
1345 		goto fail;
1346 	}
1347 
1348 	if (session->allow_multiple_registrations) {
1349 		NETAGENTLOG0(LOG_ERR, "Not allowed to register multiple agents");
1350 		response_error = NETAGENT_MESSAGE_ERROR_INVALID_DATA;
1351 		goto fail;
1352 	}
1353 
1354 	netagent_unregister_all_session_registrations(session);
1355 
1356 	netagent_send_success_response(session, NETAGENT_MESSAGE_TYPE_UNREGISTER, message_id);
1357 	return;
1358 fail:
1359 	netagent_send_error_response(session, NETAGENT_MESSAGE_TYPE_UNREGISTER, message_id, response_error);
1360 }
1361 
1362 static void
netagent_send_cellular_failed_event(struct netagent_registration * registration,pid_t pid,uuid_t proc_uuid)1363 netagent_send_cellular_failed_event(struct netagent_registration *registration,
1364     pid_t pid, uuid_t proc_uuid)
1365 {
1366 	if (strlcmp(registration->netagent->netagent_domain, "Cellular", NETAGENT_DOMAINSIZE) != 0) {
1367 		return;
1368 	}
1369 
1370 	struct kev_netpolicy_ifdenied ev_ifdenied;
1371 
1372 	bzero(&ev_ifdenied, sizeof(ev_ifdenied));
1373 
1374 	ev_ifdenied.ev_data.epid = (u_int64_t)pid;
1375 	uuid_copy(ev_ifdenied.ev_data.euuid, proc_uuid);
1376 	ev_ifdenied.ev_if_functional_type = IFRTYPE_FUNCTIONAL_CELLULAR;
1377 
1378 	netpolicy_post_msg(KEV_NETPOLICY_IFFAILED, &ev_ifdenied.ev_data, sizeof(ev_ifdenied));
1379 }
1380 
1381 static errno_t
netagent_handle_update_inner(struct netagent_session * session,struct netagent_registration * new_registration,size_t data_size,u_int8_t * agent_changed,netagent_error_domain_t error_domain)1382 netagent_handle_update_inner(struct netagent_session *session, struct netagent_registration *new_registration,
1383     size_t data_size, u_int8_t *agent_changed, netagent_error_domain_t error_domain)
1384 {
1385 	errno_t response_error = 0;
1386 
1387 	if (agent_changed == NULL) {
1388 		NETAGENTLOG0(LOG_ERR, "Invalid argument: agent_changed");
1389 		return EINVAL;
1390 	}
1391 
1392 	NETAGENT_LIST_LOCK_EXCLUSIVE();
1393 
1394 	NETAGENT_SESSION_LOCK(session);
1395 	struct netagent_registration *registration = NULL;
1396 	if (session->allow_multiple_registrations) {
1397 		registration = netagent_session_find_agent_with_uuid_and_lock(session, new_registration->netagent->netagent_uuid, true, false);
1398 	} else {
1399 		registration = netagent_session_access_agent_with_lock(session, true, false);
1400 	}
1401 
1402 	if (registration == NULL) {
1403 		NETAGENT_SESSION_UNLOCK(session);
1404 		NETAGENT_LIST_UNLOCK();
1405 		response_error = ENOENT;
1406 		return response_error;
1407 	}
1408 
1409 	if (uuid_compare(registration->netagent->netagent_uuid, new_registration->netagent->netagent_uuid) != 0 ||
1410 	    memcmp(&registration->netagent->netagent_domain, &new_registration->netagent->netagent_domain,
1411 	    sizeof(new_registration->netagent->netagent_domain)) != 0 ||
1412 	    memcmp(&registration->netagent->netagent_type, &new_registration->netagent->netagent_type,
1413 	    sizeof(new_registration->netagent->netagent_type)) != 0) {
1414 		NETAGENT_UNLOCK(registration);
1415 		NETAGENT_SESSION_UNLOCK(session);
1416 		NETAGENT_LIST_UNLOCK();
1417 		NETAGENTLOG0(LOG_ERR, "Basic agent parameters do not match, cannot update");
1418 		if (error_domain == kNetagentErrorDomainPOSIX) {
1419 			response_error = EINVAL;
1420 		} else if (error_domain == kNetagentErrorDomainUserDefined) {
1421 			response_error = NETAGENT_MESSAGE_ERROR_CANNOT_UPDATE;
1422 		}
1423 		return response_error;
1424 	}
1425 
1426 	new_registration->netagent->netagent_flags |= NETAGENT_FLAG_REGISTERED;
1427 	if (registration->netagent->netagent_data_size == new_registration->netagent->netagent_data_size &&
1428 	    memcmp(registration->netagent, new_registration->netagent, sizeof(struct netagent)) == 0 &&
1429 	    memcmp(netagent_get_data(registration->netagent), netagent_get_data(new_registration->netagent), data_size) == 0) {
1430 		// Agent is exactly identical, don't increment the generation count
1431 
1432 		// Make a copy of the list of pending clients, and clear the current list
1433 		struct netagent_client_list_s pending_triggers_list_copy;
1434 		LIST_INIT(&pending_triggers_list_copy);
1435 		struct netagent_client * __single search_client = NULL;
1436 		struct netagent_client *temp_client = NULL;
1437 		LIST_FOREACH_SAFE(search_client, &registration->pending_triggers_list, client_chain, temp_client) {
1438 			LIST_REMOVE(search_client, client_chain);
1439 			LIST_INSERT_HEAD(&pending_triggers_list_copy, search_client, client_chain);
1440 		}
1441 		NETAGENT_UNLOCK(registration);
1442 		NETAGENT_SESSION_UNLOCK(session);
1443 		NETAGENT_LIST_UNLOCK();
1444 
1445 		// Update pending client triggers without holding a lock
1446 		search_client = NULL;
1447 		temp_client = NULL;
1448 		LIST_FOREACH_SAFE(search_client, &pending_triggers_list_copy, client_chain, temp_client) {
1449 			necp_force_update_client(search_client->client_id, registration->netagent->netagent_uuid, registration->generation);
1450 			netagent_send_cellular_failed_event(new_registration, search_client->client_pid, search_client->client_proc_uuid);
1451 			LIST_REMOVE(search_client, client_chain);
1452 			kfree_type(struct netagent_client, search_client);
1453 		}
1454 		NETAGENTLOG0(LOG_DEBUG, "Updated agent (no changes)");
1455 		*agent_changed = FALSE;
1456 		return response_error;
1457 	}
1458 
1459 	new_registration->generation = g_next_generation++;
1460 	new_registration->use_count = registration->use_count;
1461 
1462 	TAILQ_INIT(&new_registration->token_list);
1463 	TAILQ_CONCAT(&new_registration->token_list, &registration->token_list, token_chain);
1464 	new_registration->token_count = registration->token_count;
1465 	new_registration->token_low_water = registration->token_low_water;
1466 	new_registration->last_client_error = registration->last_client_error;
1467 	new_registration->client_error_count = registration->client_error_count;
1468 	new_registration->allow_multiple_registrations = registration->allow_multiple_registrations;
1469 
1470 	if ((new_registration->netagent->netagent_flags & NETAGENT_FLAG_ACTIVE) &&
1471 	    !(registration->netagent->netagent_flags & NETAGENT_FLAG_ACTIVE)) {
1472 		netagent_active_count++;
1473 	} else if (!(new_registration->netagent->netagent_flags & NETAGENT_FLAG_ACTIVE) &&
1474 	    (registration->netagent->netagent_flags & NETAGENT_FLAG_ACTIVE) &&
1475 	    netagent_active_count > 0) {
1476 		netagent_active_count--;
1477 	}
1478 
1479 	TAILQ_REMOVE(&session->registrations, registration, session_chain);
1480 	LIST_REMOVE(registration, global_chain);
1481 	NETAGENT_UNLOCK(registration);
1482 	netagent_free_registration(registration);
1483 	TAILQ_INSERT_TAIL(&session->registrations, new_registration, session_chain);
1484 	new_registration->control_unit = session->control_unit;
1485 	new_registration->event_handler = session->event_handler;
1486 	new_registration->event_context = session->event_context;
1487 	LIST_INSERT_HEAD(&shared_netagent_list, new_registration, global_chain);
1488 	LIST_INIT(&new_registration->pending_triggers_list);
1489 
1490 	NETAGENT_SESSION_UNLOCK(session);
1491 	NETAGENT_LIST_UNLOCK();
1492 
1493 	NETAGENTLOG0(LOG_DEBUG, "Updated agent");
1494 	*agent_changed = TRUE;
1495 
1496 	return response_error;
1497 }
1498 
1499 errno_t
netagent_update(netagent_session_t _session,struct netagent * agent)1500 netagent_update(netagent_session_t _session, struct netagent *agent)
1501 {
1502 	u_int8_t agent_changed;
1503 	struct netagent_registration *new_registration = NULL;
1504 	bool should_update_immediately;
1505 	uuid_t updated_uuid;
1506 
1507 	struct netagent_session *session = (struct netagent_session *)_session;
1508 	if (session == NULL) {
1509 		NETAGENTLOG0(LOG_ERR, "Cannot update agent on NULL session");
1510 		return EINVAL;
1511 	}
1512 
1513 	if (agent == NULL) {
1514 		NETAGENTLOG0(LOG_ERR, "Cannot register NULL agent");
1515 		return EINVAL;
1516 	}
1517 
1518 	size_t data_size = agent->netagent_data_size;
1519 	if (data_size > NETAGENT_MAX_DATA_SIZE) {
1520 		NETAGENTLOG(LOG_ERR, "Update message size (%zu > %u) too large", data_size, NETAGENT_MAX_DATA_SIZE);
1521 		return EINVAL;
1522 	}
1523 
1524 	new_registration = netagent_alloc_registration_memory(data_size);
1525 
1526 	__nochk_memcpy(new_registration->netagent, agent, sizeof(struct netagent));
1527 	__nochk_memcpy(netagent_get_data(new_registration->netagent), netagent_get_data(agent), data_size);
1528 
1529 	uuid_copy(updated_uuid, new_registration->netagent->netagent_uuid);
1530 	should_update_immediately = (NETAGENT_FLAG_UPDATE_IMMEDIATELY == (new_registration->netagent->netagent_flags & NETAGENT_FLAG_UPDATE_IMMEDIATELY));
1531 
1532 	errno_t error = netagent_handle_update_inner(session, new_registration, data_size, &agent_changed, kNetagentErrorDomainPOSIX);
1533 	if (error == 0) {
1534 		netagent_post_event(updated_uuid, KEV_NETAGENT_UPDATED, agent_changed, should_update_immediately);
1535 		if (agent_changed == FALSE) {
1536 			// The session registration does not need the "new_registration" as nothing changed
1537 			netagent_free_registration_memory(new_registration);
1538 		}
1539 	} else {
1540 		netagent_free_registration_memory(new_registration);
1541 		return error;
1542 	}
1543 
1544 	return 0;
1545 }
1546 
1547 static errno_t
netagent_handle_update_setopt(struct netagent_session * session,u_int8_t * payload,size_t payload_length)1548 netagent_handle_update_setopt(struct netagent_session *session, u_int8_t *payload, size_t payload_length)
1549 {
1550 	struct netagent_registration *new_registration = NULL;
1551 	errno_t response_error = 0;
1552 	struct netagent *update_netagent = (struct netagent *)(void *)payload;
1553 	u_int8_t agent_changed;
1554 	bool should_update_immediately;
1555 	uuid_t updated_uuid;
1556 
1557 	if (session == NULL) {
1558 		NETAGENTLOG0(LOG_ERR, "Failed to find session");
1559 		response_error = EINVAL;
1560 		goto done;
1561 	}
1562 
1563 	if (payload == NULL) {
1564 		NETAGENTLOG0(LOG_ERR, "No payload received");
1565 		response_error = EINVAL;
1566 		goto done;
1567 	}
1568 
1569 	if (payload_length < sizeof(struct netagent)) {
1570 		NETAGENTLOG(LOG_ERR, "Update message size too small for agent: (%zu < %zu)",
1571 		    payload_length, sizeof(struct netagent));
1572 		response_error = EINVAL;
1573 		goto done;
1574 	}
1575 
1576 	size_t data_size = update_netagent->netagent_data_size;
1577 	if (data_size > NETAGENT_MAX_DATA_SIZE) {
1578 		NETAGENTLOG(LOG_ERR, "Update message size (%zu > %u) too large", data_size, NETAGENT_MAX_DATA_SIZE);
1579 		response_error = EINVAL;
1580 		goto done;
1581 	}
1582 
1583 	if (payload_length != (sizeof(struct netagent) + data_size)) {
1584 		NETAGENTLOG(LOG_ERR, "Mismatch between data size and payload length (%lu != %zu)", (sizeof(struct netagent) + data_size), payload_length);
1585 		response_error = EINVAL;
1586 		goto done;
1587 	}
1588 
1589 	new_registration = netagent_alloc_registration_memory(data_size);
1590 
1591 	__nochk_memcpy(new_registration->netagent, update_netagent, sizeof(struct netagent));
1592 	__nochk_memcpy(netagent_get_data(new_registration->netagent), netagent_get_data(update_netagent), data_size);
1593 
1594 	uuid_copy(updated_uuid, new_registration->netagent->netagent_uuid);
1595 	should_update_immediately = (NETAGENT_FLAG_UPDATE_IMMEDIATELY == (new_registration->netagent->netagent_flags & NETAGENT_FLAG_UPDATE_IMMEDIATELY));
1596 
1597 	response_error = netagent_handle_update_inner(session, new_registration, data_size, &agent_changed, kNetagentErrorDomainPOSIX);
1598 	if (response_error == 0) {
1599 		netagent_post_event(updated_uuid, KEV_NETAGENT_UPDATED, agent_changed, should_update_immediately);
1600 		if (agent_changed == FALSE) {
1601 			// The session registration does not need the "new_registration" as nothing changed
1602 			netagent_free_registration_memory(new_registration);
1603 		}
1604 	} else {
1605 		netagent_free_registration_memory(new_registration);
1606 	}
1607 
1608 done:
1609 	return response_error;
1610 }
1611 
1612 static void
netagent_handle_update_message(struct netagent_session * session,u_int32_t message_id,size_t payload_length,mbuf_t packet,size_t offset)1613 netagent_handle_update_message(struct netagent_session *session, u_int32_t message_id,
1614     size_t payload_length, mbuf_t packet, size_t offset)
1615 {
1616 	int error;
1617 	struct netagent_registration *new_registration = NULL;
1618 	u_int32_t response_error = NETAGENT_MESSAGE_ERROR_INTERNAL;
1619 	u_int8_t agent_changed;
1620 	uuid_t updated_uuid;
1621 	bool should_update_immediately;
1622 
1623 	if (session == NULL) {
1624 		NETAGENTLOG0(LOG_ERR, "Failed to find session");
1625 		response_error = NETAGENT_MESSAGE_ERROR_INTERNAL;
1626 		goto fail;
1627 	}
1628 
1629 	if (payload_length < sizeof(struct netagent)) {
1630 		NETAGENTLOG(LOG_ERR, "Update message size too small for agent: (%zu < %zu)",
1631 		    payload_length, sizeof(struct netagent));
1632 		response_error = NETAGENT_MESSAGE_ERROR_INVALID_DATA;
1633 		goto fail;
1634 	}
1635 
1636 	size_t data_size = netagent_packet_get_netagent_data_size(packet, offset, &error);
1637 	if (error || data_size > NETAGENT_MAX_DATA_SIZE) {
1638 		NETAGENTLOG(LOG_ERR, "Update message size could not be read, error %d data_size %zu",
1639 		    error, data_size);
1640 		response_error = NETAGENT_MESSAGE_ERROR_INVALID_DATA;
1641 		goto fail;
1642 	}
1643 
1644 	new_registration = netagent_alloc_registration_memory(data_size);
1645 
1646 	error = mbuf_copydata(packet, offset, new_registration->netagent_alloc_size, new_registration->netagent);
1647 	if (error) {
1648 		NETAGENTLOG(LOG_ERR, "Failed to read data into agent structure: %d", error);
1649 		netagent_free_registration_memory(new_registration);
1650 		response_error = NETAGENT_MESSAGE_ERROR_INTERNAL;
1651 		goto fail;
1652 	}
1653 
1654 	uuid_copy(updated_uuid, new_registration->netagent->netagent_uuid);
1655 	should_update_immediately = (NETAGENT_FLAG_UPDATE_IMMEDIATELY == (new_registration->netagent->netagent_flags & NETAGENT_FLAG_UPDATE_IMMEDIATELY));
1656 
1657 	response_error = (u_int32_t)netagent_handle_update_inner(session, new_registration, data_size, &agent_changed, kNetagentErrorDomainUserDefined);
1658 	if (response_error != 0) {
1659 		if (response_error == ENOENT) {
1660 			response_error = NETAGENT_MESSAGE_ERROR_NOT_REGISTERED;
1661 		}
1662 		netagent_free_registration_memory(new_registration);
1663 		goto fail;
1664 	}
1665 
1666 	netagent_send_success_response(session, NETAGENT_MESSAGE_TYPE_UPDATE, message_id);
1667 
1668 	netagent_post_event(updated_uuid, KEV_NETAGENT_UPDATED, agent_changed, should_update_immediately);
1669 
1670 	if (agent_changed == FALSE) {
1671 		// The session registration does not need the "new_registration" as nothing changed
1672 		netagent_free_registration_memory(new_registration);
1673 	}
1674 
1675 	return;
1676 fail:
1677 	netagent_send_error_response(session, NETAGENT_MESSAGE_TYPE_UPDATE, message_id, response_error);
1678 }
1679 
1680 errno_t
netagent_assign_nexus(netagent_session_t _session,uuid_t necp_client_uuid,void * __sized_by (assigned_results_length)assign_message,size_t assigned_results_length)1681 netagent_assign_nexus(netagent_session_t _session, uuid_t necp_client_uuid,
1682     void * __sized_by(assigned_results_length)assign_message, size_t assigned_results_length)
1683 {
1684 	struct netagent_session *session = (struct netagent_session *)_session;
1685 	uuid_t netagent_uuid;
1686 	if (session == NULL) {
1687 		NETAGENTLOG0(LOG_ERR, "Cannot assign nexus from NULL session");
1688 		return EINVAL;
1689 	}
1690 
1691 	NETAGENT_SESSION_LOCK(session);
1692 
1693 	struct netagent_registration *registration = netagent_session_access_agent_with_lock(session, false, false);
1694 	if (registration == NULL) {
1695 		NETAGENT_SESSION_UNLOCK(session);
1696 		NETAGENTLOG0(LOG_ERR, "Session has no matching agent");
1697 		return ENOENT;
1698 	}
1699 	uuid_copy(netagent_uuid, registration->netagent->netagent_uuid);
1700 	NETAGENT_UNLOCK(registration);
1701 	NETAGENT_SESSION_UNLOCK(session);
1702 
1703 	// Note that if the error is 0, NECP has taken over our malloc'ed buffer
1704 	int error = necp_assign_client_result(netagent_uuid, necp_client_uuid, assign_message, assigned_results_length);
1705 	if (error) {
1706 		// necp_assign_client_result returns POSIX errors; don't error for ENOENT
1707 		NETAGENTLOG((error == ENOENT ? LOG_DEBUG : LOG_ERR), "Client assignment failed: %d", error);
1708 		return error;
1709 	}
1710 
1711 	NETAGENTLOG0(LOG_DEBUG, "Agent assigned nexus properties to client");
1712 	return 0;
1713 }
1714 
1715 errno_t
netagent_update_flow_protoctl_event(netagent_session_t _session,uuid_t client_id,uint32_t protoctl_event_code,uint32_t protoctl_event_val,uint32_t protoctl_event_tcp_seq_number)1716 netagent_update_flow_protoctl_event(netagent_session_t _session,
1717     uuid_t client_id, uint32_t protoctl_event_code,
1718     uint32_t protoctl_event_val, uint32_t protoctl_event_tcp_seq_number)
1719 {
1720 	struct netagent_session *session = (struct netagent_session *)_session;
1721 	uuid_t netagent_uuid;
1722 	int error = 0;
1723 
1724 	if (session == NULL) {
1725 		NETAGENTLOG0(LOG_ERR, "Cannot assign nexus from NULL session");
1726 		return EINVAL;
1727 	}
1728 
1729 	NETAGENT_SESSION_LOCK(session);
1730 	struct netagent_registration *registration = netagent_session_access_agent_with_lock(session, false, false);
1731 	if (registration == NULL) {
1732 		NETAGENT_SESSION_UNLOCK(session);
1733 		NETAGENTLOG0(LOG_ERR, "Session has no agent");
1734 		return ENOENT;
1735 	}
1736 	uuid_copy(netagent_uuid, registration->netagent->netagent_uuid);
1737 	NETAGENT_UNLOCK(registration);
1738 	NETAGENT_SESSION_UNLOCK(session);
1739 
1740 	error = necp_update_flow_protoctl_event(netagent_uuid,
1741 	    client_id, protoctl_event_code, protoctl_event_val, protoctl_event_tcp_seq_number);
1742 
1743 	return error;
1744 }
1745 
1746 static errno_t
netagent_handle_assign_nexus_setopt(struct netagent_session * session,u_int8_t * __sized_by (payload_length)payload,size_t payload_length)1747 netagent_handle_assign_nexus_setopt(struct netagent_session *session, u_int8_t * __sized_by(payload_length)payload,
1748     size_t payload_length)
1749 {
1750 	errno_t response_error = 0;
1751 	uuid_t client_id;
1752 	uuid_t netagent_uuid;
1753 	u_int8_t *assigned_results = NULL;
1754 
1755 	if (session == NULL) {
1756 		NETAGENTLOG0(LOG_ERR, "Failed to find session");
1757 		response_error = ENOENT;
1758 		goto done;
1759 	}
1760 
1761 	if (payload == NULL) {
1762 		NETAGENTLOG0(LOG_ERR, "No payload received");
1763 		response_error = EINVAL;
1764 		goto done;
1765 	}
1766 
1767 	NETAGENT_SESSION_LOCK(session);
1768 
1769 	const size_t header_offset = (session->allow_multiple_registrations ? sizeof(uuid_t) : 0);
1770 	if (payload_length < header_offset) {
1771 		NETAGENT_SESSION_UNLOCK(session);
1772 		NETAGENTLOG0(LOG_ERR, "Assign message is too short");
1773 		response_error = EINVAL;
1774 		goto done;
1775 	}
1776 
1777 	struct netagent_assign_nexus_message * __single assign_nexus_netagent = (struct netagent_assign_nexus_message *)(void *)((u_int8_t *)payload + header_offset);
1778 
1779 	struct netagent_registration *registration = NULL;
1780 	if (session->allow_multiple_registrations) {
1781 		uuid_t agent_uuid = {};
1782 		uuid_copy(agent_uuid, payload);
1783 		registration = netagent_session_find_agent_with_uuid_and_lock(session, agent_uuid, false, false);
1784 	} else {
1785 		registration = netagent_session_access_agent_with_lock(session, false, false);
1786 	}
1787 
1788 	if (registration == NULL) {
1789 		NETAGENT_SESSION_UNLOCK(session);
1790 		NETAGENTLOG0(LOG_ERR, "Session has no agent to get");
1791 		response_error = ENOENT;
1792 		goto done;
1793 	}
1794 
1795 	uuid_copy(netagent_uuid, registration->netagent->netagent_uuid);
1796 	NETAGENT_UNLOCK(registration);
1797 	NETAGENT_SESSION_UNLOCK(session);
1798 
1799 	if (payload_length < (header_offset + sizeof(uuid_t))) {
1800 		NETAGENTLOG0(LOG_ERR, "Assign message is too short");
1801 		response_error = EINVAL;
1802 		goto done;
1803 	}
1804 
1805 	memcpy(client_id, assign_nexus_netagent->assign_client_id, sizeof(client_id));
1806 	size_t assigned_results_length = (payload_length - (header_offset + sizeof(client_id)));
1807 
1808 	if (assigned_results_length > 0) {
1809 		assigned_results = kalloc_data(assigned_results_length, Z_WAITOK);
1810 		if (assigned_results == NULL) {
1811 			NETAGENTLOG(LOG_ERR, "Failed to allocate assign message (%lu bytes)", assigned_results_length);
1812 			response_error = ENOMEM;
1813 			goto done;
1814 		}
1815 		memcpy(assigned_results,
1816 		    netagent_assign_message_get_necp_result(assign_nexus_netagent, assigned_results_length),
1817 		    assigned_results_length);
1818 	}
1819 
1820 	// Note that if the error is 0, NECP has taken over our malloc'ed buffer
1821 	response_error = necp_assign_client_result(netagent_uuid, client_id, assigned_results, assigned_results_length);
1822 	if (response_error) {
1823 		// necp_assign_client_result returns POSIX errors
1824 		kfree_data(assigned_results, assigned_results_length);
1825 		NETAGENTLOG(LOG_ERR, "Client assignment failed: %d", response_error);
1826 		goto done;
1827 	}
1828 
1829 	NETAGENTLOG0(LOG_DEBUG, "Agent assigned nexus properties to client");
1830 done:
1831 	return response_error;
1832 }
1833 
1834 static void
netagent_handle_assign_nexus_message(struct netagent_session * session,u_int32_t message_id,size_t payload_length,mbuf_t packet,size_t offset)1835 netagent_handle_assign_nexus_message(struct netagent_session *session, u_int32_t message_id,
1836     size_t payload_length, mbuf_t packet, size_t offset)
1837 {
1838 	int error = 0;
1839 	u_int32_t response_error = NETAGENT_MESSAGE_ERROR_INTERNAL;
1840 	uuid_t client_id;
1841 	uuid_t netagent_uuid;
1842 	u_int8_t * assigned_results = NULL;
1843 
1844 	if (session == NULL) {
1845 		NETAGENTLOG0(LOG_ERR, "Failed to find session");
1846 		response_error = NETAGENT_MESSAGE_ERROR_INTERNAL;
1847 		goto fail;
1848 	}
1849 
1850 	NETAGENT_SESSION_LOCK(session);
1851 	struct netagent_registration *registration = netagent_session_access_agent_with_lock(session, false, false);
1852 	if (registration == NULL) {
1853 		NETAGENT_SESSION_UNLOCK(session);
1854 		NETAGENTLOG0(LOG_ERR, "Session has no agent to get");
1855 		response_error = NETAGENT_MESSAGE_ERROR_NOT_REGISTERED;
1856 		goto fail;
1857 	}
1858 	uuid_copy(netagent_uuid, registration->netagent->netagent_uuid);
1859 	NETAGENT_UNLOCK(registration);
1860 	NETAGENT_SESSION_UNLOCK(session);
1861 
1862 	if (payload_length < sizeof(uuid_t)) {
1863 		NETAGENTLOG0(LOG_ERR, "Assign message is too short");
1864 		response_error = NETAGENT_MESSAGE_ERROR_INVALID_DATA;
1865 		goto fail;
1866 	}
1867 
1868 	error = mbuf_copydata(packet, offset, sizeof(client_id), &client_id);
1869 	if (error) {
1870 		NETAGENTLOG(LOG_ERR, "Failed to read uuid for assign message: %d", error);
1871 		response_error = NETAGENT_MESSAGE_ERROR_INTERNAL;
1872 		goto fail;
1873 	}
1874 
1875 	size_t assigned_results_length = (payload_length - sizeof(client_id));
1876 	if (assigned_results_length > 0) {
1877 		assigned_results = kalloc_data( assigned_results_length, Z_WAITOK);
1878 		if (assigned_results == NULL) {
1879 			NETAGENTLOG(LOG_ERR, "Failed to allocate assign message (%lu bytes)", assigned_results_length);
1880 			response_error = NETAGENT_MESSAGE_ERROR_INTERNAL;
1881 			goto fail;
1882 		}
1883 
1884 		error = mbuf_copydata(packet, offset + sizeof(client_id), assigned_results_length, assigned_results);
1885 		if (error) {
1886 			kfree_data(assigned_results, assigned_results_length);
1887 			NETAGENTLOG(LOG_ERR, "Failed to read assign message: %d", error);
1888 			response_error = NETAGENT_MESSAGE_ERROR_INTERNAL;
1889 			goto fail;
1890 		}
1891 	}
1892 
1893 	// Note that if the error is 0, NECP has taken over our malloc'ed buffer
1894 	error = necp_assign_client_result(netagent_uuid, client_id, assigned_results, assigned_results_length);
1895 	if (error) {
1896 		kfree_data(assigned_results, assigned_results_length);
1897 		NETAGENTLOG(LOG_ERR, "Client assignment failed: %d", error);
1898 		response_error = NETAGENT_MESSAGE_ERROR_CANNOT_ASSIGN;
1899 		goto fail;
1900 	}
1901 
1902 	NETAGENTLOG0(LOG_DEBUG, "Agent assigned nexus properties to client");
1903 	netagent_send_success_response(session, NETAGENT_MESSAGE_TYPE_ASSIGN_NEXUS, message_id);
1904 	return;
1905 fail:
1906 	netagent_send_error_response(session, NETAGENT_MESSAGE_TYPE_ASSIGN_NEXUS, message_id, response_error);
1907 }
1908 
1909 static errno_t
netagent_handle_assign_group_setopt(struct netagent_session * session,u_int8_t * __sized_by (payload_length)payload,size_t payload_length)1910 netagent_handle_assign_group_setopt(struct netagent_session *session, u_int8_t * __sized_by(payload_length)payload,
1911     size_t payload_length)
1912 {
1913 	errno_t response_error = 0;
1914 	uuid_t client_id;
1915 	uuid_t netagent_uuid;
1916 	u_int8_t *assigned_group_members = NULL;
1917 
1918 	if (session == NULL) {
1919 		NETAGENTLOG0(LOG_ERR, "Failed to find session");
1920 		response_error = ENOENT;
1921 		goto done;
1922 	}
1923 
1924 	if (payload == NULL) {
1925 		NETAGENTLOG0(LOG_ERR, "No payload received");
1926 		response_error = EINVAL;
1927 		goto done;
1928 	}
1929 
1930 	NETAGENT_SESSION_LOCK(session);
1931 
1932 	const size_t header_offset = (session->allow_multiple_registrations ? sizeof(uuid_t) : 0);
1933 	if (payload_length < header_offset) {
1934 		NETAGENT_SESSION_UNLOCK(session);
1935 		NETAGENTLOG0(LOG_ERR, "Assign message is too short");
1936 		response_error = EINVAL;
1937 		goto done;
1938 	}
1939 
1940 	struct netagent_assign_nexus_message *assign_message = (struct netagent_assign_nexus_message *)(void *)((u_int8_t *)payload + header_offset);
1941 
1942 	struct netagent_registration *registration = NULL;
1943 	if (session->allow_multiple_registrations) {
1944 		uuid_t agent_uuid = {};
1945 		uuid_copy(agent_uuid, payload);
1946 		registration = netagent_session_find_agent_with_uuid_and_lock(session, agent_uuid, false, false);
1947 	} else {
1948 		registration = netagent_session_access_agent_with_lock(session, false, false);
1949 	}
1950 
1951 	if (registration == NULL) {
1952 		NETAGENT_SESSION_UNLOCK(session);
1953 		NETAGENTLOG0(LOG_ERR, "Session has no agent to get");
1954 		response_error = ENOENT;
1955 		goto done;
1956 	}
1957 
1958 	uuid_copy(netagent_uuid, registration->netagent->netagent_uuid);
1959 	NETAGENT_UNLOCK(registration);
1960 	NETAGENT_SESSION_UNLOCK(session);
1961 
1962 	if (payload_length < (header_offset + sizeof(uuid_t))) {
1963 		NETAGENTLOG0(LOG_ERR, "Group assign message is too short");
1964 		response_error = EINVAL;
1965 		goto done;
1966 	}
1967 
1968 	memcpy(client_id, assign_message->assign_client_id, sizeof(client_id));
1969 	size_t assigned_group_members_length = (payload_length - (header_offset + sizeof(client_id)));
1970 
1971 	if (assigned_group_members_length > 0) {
1972 		assigned_group_members = (u_int8_t *)kalloc_data(assigned_group_members_length, Z_WAITOK);
1973 		if (assigned_group_members == NULL) {
1974 			NETAGENTLOG(LOG_ERR, "Failed to allocate group assign message (%lu bytes)", assigned_group_members_length);
1975 			response_error = ENOMEM;
1976 			goto done;
1977 		}
1978 		memcpy(assigned_group_members, netagent_assign_message_get_necp_result(assign_message, assigned_group_members_length), assigned_group_members_length);
1979 	}
1980 
1981 	// Note that if the error is 0, NECP has taken over our malloc'ed buffer
1982 	response_error = necp_assign_client_group_members(netagent_uuid, client_id, assigned_group_members, assigned_group_members_length);
1983 	if (response_error != 0) {
1984 		// necp_assign_client_group_members returns POSIX errors
1985 		if (assigned_group_members != NULL) {
1986 			kfree_data(assigned_group_members, assigned_group_members_length);
1987 		}
1988 		NETAGENTLOG(LOG_ERR, "Client group assignment failed: %d", response_error);
1989 		goto done;
1990 	}
1991 
1992 	NETAGENTLOG0(LOG_DEBUG, "Agent assigned group members to client");
1993 done:
1994 	return response_error;
1995 }
1996 
1997 errno_t
netagent_handle_use_count_setopt(struct netagent_session * session,u_int8_t * __sized_by (payload_length)payload,size_t payload_length)1998 netagent_handle_use_count_setopt(struct netagent_session *session, u_int8_t * __sized_by(payload_length)payload, size_t payload_length)
1999 {
2000 	errno_t response_error = 0;
2001 	uint64_t use_count = 0;
2002 
2003 	if (session == NULL) {
2004 		NETAGENTLOG0(LOG_ERR, "Failed to find session");
2005 		response_error = ENOENT;
2006 		goto done;
2007 	}
2008 
2009 	if (payload == NULL) {
2010 		NETAGENTLOG0(LOG_ERR, "No payload received");
2011 		response_error = EINVAL;
2012 		goto done;
2013 	}
2014 
2015 	NETAGENT_SESSION_LOCK(session);
2016 	const size_t header_offset = (session->allow_multiple_registrations ? sizeof(uuid_t) : 0);
2017 	const size_t expected_length = header_offset + sizeof(use_count);
2018 	if (payload_length != expected_length) {
2019 		NETAGENT_SESSION_UNLOCK(session);
2020 		NETAGENTLOG(LOG_ERR, "Payload length is invalid (%lu)", payload_length);
2021 		response_error = EINVAL;
2022 		goto done;
2023 	}
2024 
2025 	memcpy(&use_count, payload + header_offset, sizeof(use_count));
2026 
2027 	struct netagent_registration *registration = NULL;
2028 	if (session->allow_multiple_registrations) {
2029 		uuid_t agent_uuid = {};
2030 		uuid_copy(agent_uuid, payload);
2031 		registration = netagent_session_find_agent_with_uuid_and_lock(session, agent_uuid, false, false);
2032 	} else {
2033 		registration = netagent_session_access_agent_with_lock(session, true, false);
2034 	}
2035 
2036 	if (registration == NULL) {
2037 		NETAGENT_SESSION_UNLOCK(session);
2038 		NETAGENTLOG0(LOG_ERR, "Session has no agent registered");
2039 		response_error = ENOENT;
2040 		goto done;
2041 	}
2042 
2043 	registration->use_count = use_count;
2044 	NETAGENT_UNLOCK(registration);
2045 	NETAGENT_SESSION_UNLOCK(session);
2046 
2047 done:
2048 	return response_error;
2049 }
2050 
2051 errno_t
netagent_handle_use_count_getopt(struct netagent_session * session,u_int8_t * __sized_by (* buffer_length)buffer,size_t * buffer_length)2052 netagent_handle_use_count_getopt(struct netagent_session *session, u_int8_t * __sized_by(*buffer_length)buffer, size_t *buffer_length)
2053 {
2054 	errno_t response_error = 0;
2055 	uint64_t use_count = 0;
2056 
2057 	if (session == NULL) {
2058 		NETAGENTLOG0(LOG_ERR, "Failed to find session");
2059 		response_error = ENOENT;
2060 		goto done;
2061 	}
2062 
2063 	if (buffer == NULL) {
2064 		NETAGENTLOG0(LOG_ERR, "No payload received");
2065 		response_error = EINVAL;
2066 		goto done;
2067 	}
2068 
2069 	NETAGENT_SESSION_LOCK(session);
2070 	const size_t header_offset = (session->allow_multiple_registrations ? sizeof(uuid_t) : 0);
2071 	const size_t expected_length = header_offset + sizeof(use_count);
2072 	if (*buffer_length != expected_length) {
2073 		NETAGENT_SESSION_UNLOCK(session);
2074 		NETAGENTLOG(LOG_ERR, "Buffer length is invalid (%lu)", *buffer_length);
2075 		response_error = EINVAL;
2076 		goto done;
2077 	}
2078 
2079 	struct netagent_registration *registration = NULL;
2080 	if (session->allow_multiple_registrations) {
2081 		uuid_t agent_uuid = {};
2082 		uuid_copy(agent_uuid, buffer);
2083 		registration = netagent_session_find_agent_with_uuid_and_lock(session, agent_uuid, false, false);
2084 	} else {
2085 		registration = netagent_session_access_agent_with_lock(session, false, false);
2086 	}
2087 
2088 	if (registration == NULL) {
2089 		NETAGENT_SESSION_UNLOCK(session);
2090 		NETAGENTLOG0(LOG_ERR, "Session has no agent registered");
2091 		response_error = ENOENT;
2092 		goto done;
2093 	}
2094 
2095 	use_count = registration->use_count;
2096 	NETAGENT_UNLOCK(registration);
2097 	NETAGENT_SESSION_UNLOCK(session);
2098 
2099 	memcpy(buffer + header_offset, &use_count, sizeof(use_count));
2100 	*buffer_length = (header_offset + sizeof(use_count));
2101 
2102 done:
2103 	return response_error;
2104 }
2105 
2106 static errno_t
netagent_handle_add_token_setopt(struct netagent_session * session,u_int8_t * __sized_by (token_length)token,size_t token_length)2107 netagent_handle_add_token_setopt(struct netagent_session *session, u_int8_t * __sized_by(token_length)token, size_t token_length)
2108 {
2109 	errno_t response_error = 0;
2110 
2111 	if (session == NULL) {
2112 		NETAGENTLOG0(LOG_ERR, "Failed to find session");
2113 		response_error = ENOENT;
2114 		goto done;
2115 	}
2116 
2117 	if (token == NULL) {
2118 		NETAGENTLOG0(LOG_ERR, "No token received");
2119 		response_error = EINVAL;
2120 		goto done;
2121 	}
2122 
2123 	NETAGENT_SESSION_LOCK(session);
2124 	const size_t header_offset = (session->allow_multiple_registrations ? sizeof(uuid_t) : 0);
2125 	if (token_length > (header_offset + NETAGENT_MAX_DATA_SIZE) ||
2126 	    token_length < header_offset) {
2127 		NETAGENT_SESSION_UNLOCK(session);
2128 		NETAGENTLOG(LOG_ERR, "Token length is invalid (%lu)", token_length);
2129 		response_error = EINVAL;
2130 		goto done;
2131 	}
2132 
2133 	struct netagent_registration *registration = NULL;
2134 	if (session->allow_multiple_registrations) {
2135 		uuid_t agent_uuid = {};
2136 		uuid_copy(agent_uuid, token);
2137 		registration = netagent_session_find_agent_with_uuid_and_lock(session, agent_uuid, true, false);
2138 	} else {
2139 		registration = netagent_session_access_agent_with_lock(session, true, false);
2140 	}
2141 
2142 	if (registration == NULL) {
2143 		NETAGENT_SESSION_UNLOCK(session);
2144 		NETAGENTLOG0(LOG_ERR, "Session has no agent registered");
2145 		response_error = ENOENT;
2146 		goto done;
2147 	}
2148 
2149 	if (registration->token_count >= NETAGENT_MAX_TOKEN_COUNT) {
2150 		NETAGENT_UNLOCK(registration);
2151 		NETAGENT_SESSION_UNLOCK(session);
2152 		NETAGENTLOG0(LOG_ERR, "Session cannot add more tokens");
2153 		response_error = EINVAL;
2154 		goto done;
2155 	}
2156 
2157 	struct netagent_token *token_struct = NULL;
2158 
2159 	token_struct = kalloc_type(struct netagent_token, Z_WAITOK | Z_ZERO | Z_NOFAIL);
2160 	token_struct->token_bytes = kalloc_data((token_length - header_offset), Z_WAITOK | Z_NOFAIL);
2161 	token_struct->token_length = (u_int32_t)(token_length - header_offset);
2162 	memcpy(token_struct->token_bytes, token + header_offset, (token_length - header_offset));
2163 
2164 	TAILQ_INSERT_TAIL(&registration->token_list, token_struct, token_chain);
2165 
2166 	registration->token_count++;
2167 
2168 	// Reset deadline time, now that there are more than 0 tokens
2169 	registration->need_tokens_event_deadline = 0;
2170 
2171 	NETAGENT_UNLOCK(registration);
2172 	NETAGENT_SESSION_UNLOCK(session);
2173 done:
2174 	return response_error;
2175 }
2176 
2177 static errno_t
netagent_handle_flush_tokens_setopt(struct netagent_session * session,u_int8_t * __sized_by (buffer_length)buffer,size_t buffer_length)2178 netagent_handle_flush_tokens_setopt(struct netagent_session *session, u_int8_t * __sized_by(buffer_length)buffer, size_t buffer_length)
2179 {
2180 	errno_t response_error = 0;
2181 
2182 	if (session == NULL) {
2183 		NETAGENTLOG0(LOG_ERR, "Failed to find session");
2184 		response_error = ENOENT;
2185 		goto done;
2186 	}
2187 
2188 	NETAGENT_SESSION_LOCK(session);
2189 	struct netagent_registration *registration = NULL;
2190 	if (session->allow_multiple_registrations) {
2191 		if (buffer_length != sizeof(uuid_t)) {
2192 			NETAGENT_SESSION_UNLOCK(session);
2193 			NETAGENTLOG(LOG_ERR, "Buffer length is invalid (%lu)", buffer_length);
2194 			response_error = EINVAL;
2195 			goto done;
2196 		}
2197 
2198 		uuid_t agent_uuid = {};
2199 		uuid_copy(agent_uuid, buffer);
2200 		registration = netagent_session_find_agent_with_uuid_and_lock(session, agent_uuid, true, false);
2201 	} else {
2202 		registration = netagent_session_access_agent_with_lock(session, true, false);
2203 	}
2204 
2205 	if (registration == NULL) {
2206 		NETAGENT_SESSION_UNLOCK(session);
2207 		NETAGENTLOG0(LOG_ERR, "Session has no agent registered");
2208 		response_error = ENOENT;
2209 		goto done;
2210 	}
2211 
2212 	struct netagent_token *search_token = NULL;
2213 	struct netagent_token *temp_token = NULL;
2214 	TAILQ_FOREACH_SAFE(search_token, &registration->token_list, token_chain, temp_token) {
2215 		TAILQ_REMOVE(&registration->token_list, search_token, token_chain);
2216 		netagent_token_free(search_token);
2217 	}
2218 	registration->token_count = 0;
2219 	NETAGENT_UNLOCK(registration);
2220 	NETAGENT_SESSION_UNLOCK(session);
2221 done:
2222 	return response_error;
2223 }
2224 
2225 static errno_t
netagent_handle_token_count_getopt(struct netagent_session * session,u_int8_t * __sized_by (* buffer_length)buffer,size_t * buffer_length)2226 netagent_handle_token_count_getopt(struct netagent_session *session, u_int8_t * __sized_by(*buffer_length)buffer, size_t *buffer_length)
2227 {
2228 	errno_t response_error = 0;
2229 	uint32_t token_count = 0;
2230 
2231 	if (session == NULL) {
2232 		NETAGENTLOG0(LOG_ERR, "Failed to find session");
2233 		response_error = ENOENT;
2234 		goto done;
2235 	}
2236 
2237 	if (buffer == NULL) {
2238 		NETAGENTLOG0(LOG_ERR, "No payload received");
2239 		response_error = EINVAL;
2240 		goto done;
2241 	}
2242 
2243 	NETAGENT_SESSION_LOCK(session);
2244 	const size_t header_offset = (session->allow_multiple_registrations ? sizeof(uuid_t) : 0);
2245 	const size_t expected_length = header_offset + sizeof(token_count);
2246 	if (*buffer_length != expected_length) {
2247 		NETAGENT_SESSION_UNLOCK(session);
2248 		NETAGENTLOG(LOG_ERR, "Buffer length is invalid (%lu)", *buffer_length);
2249 		response_error = EINVAL;
2250 		goto done;
2251 	}
2252 
2253 	struct netagent_registration *registration = NULL;
2254 	if (session->allow_multiple_registrations) {
2255 		uuid_t agent_uuid = {};
2256 		uuid_copy(agent_uuid, buffer);
2257 		registration = netagent_session_find_agent_with_uuid_and_lock(session, agent_uuid, false, false);
2258 	} else {
2259 		registration = netagent_session_access_agent_with_lock(session, false, false);
2260 	}
2261 
2262 	if (registration == NULL) {
2263 		NETAGENT_SESSION_UNLOCK(session);
2264 		NETAGENTLOG0(LOG_ERR, "Session has no agent registered");
2265 		response_error = ENOENT;
2266 		goto done;
2267 	}
2268 
2269 	token_count = registration->token_count;
2270 	NETAGENT_UNLOCK(registration);
2271 	NETAGENT_SESSION_UNLOCK(session);
2272 
2273 	memcpy(buffer + header_offset, &token_count, sizeof(token_count));
2274 	*buffer_length = (header_offset + sizeof(token_count));
2275 
2276 done:
2277 	return response_error;
2278 }
2279 
2280 static errno_t
netagent_handle_token_low_water_setopt(struct netagent_session * session,u_int8_t * __sized_by (buffer_length)buffer,size_t buffer_length)2281 netagent_handle_token_low_water_setopt(struct netagent_session *session, u_int8_t * __sized_by(buffer_length)buffer, size_t buffer_length)
2282 {
2283 	errno_t response_error = 0;
2284 	uint32_t token_low_water = 0;
2285 
2286 	if (session == NULL) {
2287 		NETAGENTLOG0(LOG_ERR, "Failed to find session");
2288 		response_error = ENOENT;
2289 		goto done;
2290 	}
2291 
2292 	if (buffer == NULL) {
2293 		NETAGENTLOG0(LOG_ERR, "No payload received");
2294 		response_error = EINVAL;
2295 		goto done;
2296 	}
2297 
2298 	NETAGENT_SESSION_LOCK(session);
2299 	const size_t header_offset = (session->allow_multiple_registrations ? sizeof(uuid_t) : 0);
2300 	const size_t expected_length = header_offset + sizeof(token_low_water);
2301 	if (buffer_length != expected_length) {
2302 		NETAGENT_SESSION_UNLOCK(session);
2303 		NETAGENTLOG(LOG_ERR, "Buffer length is invalid (%lu)", buffer_length);
2304 		response_error = EINVAL;
2305 		goto done;
2306 	}
2307 
2308 	memcpy(&token_low_water, buffer + header_offset, sizeof(token_low_water));
2309 
2310 	struct netagent_registration *registration = NULL;
2311 	if (session->allow_multiple_registrations) {
2312 		uuid_t agent_uuid = {};
2313 		uuid_copy(agent_uuid, buffer);
2314 		registration = netagent_session_find_agent_with_uuid_and_lock(session, agent_uuid, true, false);
2315 	} else {
2316 		registration = netagent_session_access_agent_with_lock(session, true, false);
2317 	}
2318 
2319 	if (registration == NULL) {
2320 		NETAGENT_SESSION_UNLOCK(session);
2321 		NETAGENTLOG0(LOG_ERR, "Session has no agent registered");
2322 		response_error = ENOENT;
2323 		goto done;
2324 	}
2325 
2326 	registration->token_low_water = token_low_water;
2327 	NETAGENT_UNLOCK(registration);
2328 	NETAGENT_SESSION_UNLOCK(session);
2329 
2330 done:
2331 	return response_error;
2332 }
2333 
2334 static errno_t
netagent_handle_token_low_water_getopt(struct netagent_session * session,u_int8_t * __sized_by (* buffer_length)buffer,size_t * buffer_length)2335 netagent_handle_token_low_water_getopt(struct netagent_session *session, u_int8_t * __sized_by(*buffer_length)buffer, size_t *buffer_length)
2336 {
2337 	errno_t response_error = 0;
2338 	uint32_t token_low_water = 0;
2339 
2340 	if (session == NULL) {
2341 		NETAGENTLOG0(LOG_ERR, "Failed to find session");
2342 		response_error = ENOENT;
2343 		goto done;
2344 	}
2345 
2346 	if (buffer == NULL) {
2347 		NETAGENTLOG0(LOG_ERR, "No payload received");
2348 		response_error = EINVAL;
2349 		goto done;
2350 	}
2351 
2352 	NETAGENT_SESSION_LOCK(session);
2353 	const size_t header_offset = (session->allow_multiple_registrations ? sizeof(uuid_t) : 0);
2354 	const size_t expected_length = header_offset + sizeof(token_low_water);
2355 	if (*buffer_length != expected_length) {
2356 		NETAGENT_SESSION_UNLOCK(session);
2357 		NETAGENTLOG(LOG_ERR, "Buffer length is invalid (%lu)", *buffer_length);
2358 		response_error = EINVAL;
2359 		goto done;
2360 	}
2361 
2362 	struct netagent_registration *registration = NULL;
2363 	if (session->allow_multiple_registrations) {
2364 		uuid_t agent_uuid = {};
2365 		uuid_copy(agent_uuid, buffer);
2366 		registration = netagent_session_find_agent_with_uuid_and_lock(session, agent_uuid, false, false);
2367 	} else {
2368 		registration = netagent_session_access_agent_with_lock(session, false, false);
2369 	}
2370 
2371 	if (registration == NULL) {
2372 		NETAGENT_SESSION_UNLOCK(session);
2373 		NETAGENTLOG0(LOG_ERR, "Session has no agent registered");
2374 		response_error = ENOENT;
2375 		goto done;
2376 	}
2377 
2378 	token_low_water = registration->token_low_water;
2379 	NETAGENT_UNLOCK(registration);
2380 	NETAGENT_SESSION_UNLOCK(session);
2381 
2382 	memcpy(buffer + header_offset, &token_low_water, sizeof(token_low_water));
2383 	*buffer_length = (header_offset + sizeof(token_low_water));
2384 
2385 done:
2386 	return response_error;
2387 }
2388 
2389 static errno_t
netagent_handle_reset_client_error_setopt(struct netagent_session * session,u_int8_t * __sized_by (payload_length)payload,size_t payload_length)2390 netagent_handle_reset_client_error_setopt(struct netagent_session *session, u_int8_t * __sized_by(payload_length)payload, size_t payload_length)
2391 {
2392 	errno_t response_error = 0;
2393 
2394 	if (session == NULL) {
2395 		NETAGENTLOG0(LOG_ERR, "Failed to find session");
2396 		response_error = ENOENT;
2397 		goto done;
2398 	}
2399 
2400 	NETAGENT_SESSION_LOCK(session);
2401 	struct netagent_registration *registration = NULL;
2402 	if (session->allow_multiple_registrations) {
2403 		if (payload_length != sizeof(uuid_t)) {
2404 			NETAGENT_SESSION_UNLOCK(session);
2405 			NETAGENTLOG(LOG_ERR, "Payload length is invalid (%lu)", payload_length);
2406 			response_error = EINVAL;
2407 			goto done;
2408 		}
2409 
2410 		uuid_t agent_uuid = {};
2411 		uuid_copy(agent_uuid, payload);
2412 		registration = netagent_session_find_agent_with_uuid_and_lock(session, agent_uuid, true, false);
2413 	} else {
2414 		registration = netagent_session_access_agent_with_lock(session, true, false);
2415 	}
2416 
2417 	if (registration == NULL) {
2418 		NETAGENT_SESSION_UNLOCK(session);
2419 		NETAGENTLOG0(LOG_ERR, "Session has no agent registered");
2420 		response_error = ENOENT;
2421 		goto done;
2422 	}
2423 
2424 	struct netagent_token *search_token = NULL;
2425 	struct netagent_token *temp_token = NULL;
2426 	TAILQ_FOREACH_SAFE(search_token, &registration->token_list, token_chain, temp_token) {
2427 		TAILQ_REMOVE(&registration->token_list, search_token, token_chain);
2428 		netagent_token_free(search_token);
2429 	}
2430 	registration->last_client_error = 0;
2431 	registration->client_error_count = 0;
2432 
2433 	NETAGENT_UNLOCK(registration);
2434 	NETAGENT_SESSION_UNLOCK(session);
2435 done:
2436 	return response_error;
2437 }
2438 
2439 static errno_t
netagent_handle_enable_session_mode_setopt(struct netagent_session * session,__unused u_int8_t * payload,__unused size_t payload_length)2440 netagent_handle_enable_session_mode_setopt(struct netagent_session *session, __unused u_int8_t *payload, __unused size_t payload_length)
2441 {
2442 	errno_t response_error = 0;
2443 
2444 	if (session == NULL) {
2445 		NETAGENTLOG0(LOG_ERR, "Failed to find session");
2446 		response_error = ENOENT;
2447 		goto done;
2448 	}
2449 
2450 	NETAGENT_SESSION_LOCK(session);
2451 	if (!TAILQ_EMPTY(&session->registrations)) {
2452 		NETAGENT_SESSION_UNLOCK(session);
2453 		NETAGENTLOG0(LOG_ERR, "Session already has agent registered");
2454 		response_error = EEXIST;
2455 		goto done;
2456 	}
2457 
2458 	session->allow_multiple_registrations = true;
2459 	NETAGENT_SESSION_UNLOCK(session);
2460 done:
2461 	return response_error;
2462 }
2463 
2464 static struct netagent_registration *
netagent_find_agent_with_uuid_and_lock(uuid_t uuid,bool exclusively,bool ignore_lock)2465 netagent_find_agent_with_uuid_and_lock(uuid_t uuid, bool exclusively, bool ignore_lock)
2466 {
2467 	NETAGENT_LIST_ASSERT_LOCKED();
2468 
2469 	struct netagent_registration *registration = NULL;
2470 	LIST_FOREACH(registration, &shared_netagent_list, global_chain) {
2471 		if (uuid_compare(registration->netagent->netagent_uuid, uuid) == 0) {
2472 			if (!ignore_lock) {
2473 				if (exclusively) {
2474 					NETAGENT_LOCK_EXCLUSIVE(registration);
2475 				} else {
2476 					NETAGENT_LOCK_SHARED(registration);
2477 				}
2478 			}
2479 			return registration;
2480 		}
2481 	}
2482 
2483 	return NULL;
2484 }
2485 
2486 static struct netagent_registration *
netagent_session_find_agent_with_uuid_and_lock(struct netagent_session * session,uuid_t uuid,bool exclusively,bool ignore_lock)2487 netagent_session_find_agent_with_uuid_and_lock(struct netagent_session *session, uuid_t uuid, bool exclusively, bool ignore_lock)
2488 {
2489 	NETAGENT_SESSION_ASSERT_LOCKED(session);
2490 
2491 	struct netagent_registration *registration = NULL;
2492 	TAILQ_FOREACH(registration, &session->registrations, session_chain) {
2493 		if (uuid_compare(registration->netagent->netagent_uuid, uuid) == 0) {
2494 			if (!ignore_lock) {
2495 				if (exclusively) {
2496 					NETAGENT_LOCK_EXCLUSIVE(registration);
2497 				} else {
2498 					NETAGENT_LOCK_SHARED(registration);
2499 				}
2500 			}
2501 			return registration;
2502 		}
2503 	}
2504 
2505 	return NULL;
2506 }
2507 
2508 static struct netagent_registration *
netagent_session_access_agent_with_lock(struct netagent_session * session,bool exclusively,bool ignore_lock)2509 netagent_session_access_agent_with_lock(struct netagent_session *session, bool exclusively, bool ignore_lock)
2510 {
2511 	NETAGENT_SESSION_ASSERT_LOCKED(session);
2512 
2513 	struct netagent_registration *registration = TAILQ_FIRST(&session->registrations);
2514 	if (registration != NULL) {
2515 		if (!ignore_lock) {
2516 			if (exclusively) {
2517 				NETAGENT_LOCK_EXCLUSIVE(registration);
2518 			} else {
2519 				NETAGENT_LOCK_SHARED(registration);
2520 			}
2521 		}
2522 	}
2523 
2524 	return registration;
2525 }
2526 
2527 void
netagent_post_updated_interfaces(uuid_t uuid)2528 netagent_post_updated_interfaces(uuid_t uuid)
2529 {
2530 	if (!uuid_is_null(uuid)) {
2531 		netagent_post_event(uuid, KEV_NETAGENT_UPDATED_INTERFACES, true, false);
2532 	} else {
2533 		NETAGENTLOG0(LOG_DEBUG, "Interface event with no associated agent");
2534 	}
2535 }
2536 
2537 static u_int32_t
netagent_dump_get_data_size_locked()2538 netagent_dump_get_data_size_locked()
2539 {
2540 	NETAGENT_LIST_ASSERT_LOCKED();
2541 
2542 	struct netagent_registration *search_netagent = NULL;
2543 	u_int32_t total_netagent_data_size = 0;
2544 	// Traverse the shared list to know how much data the client needs to allocate to get the list of agent UUIDs
2545 	LIST_FOREACH(search_netagent, &shared_netagent_list, global_chain) {
2546 		total_netagent_data_size += sizeof(search_netagent->netagent->netagent_uuid);
2547 	}
2548 	return total_netagent_data_size;
2549 }
2550 
2551 static void
netagent_dump_copy_data_locked(u_int8_t * __sized_by (buffer_length)buffer,u_int32_t buffer_length)2552 netagent_dump_copy_data_locked(u_int8_t * __sized_by(buffer_length)buffer, u_int32_t buffer_length)
2553 {
2554 	NETAGENT_LIST_ASSERT_LOCKED();
2555 
2556 	size_t response_size = 0;
2557 	u_int8_t * __indexable cursor = NULL;
2558 	struct netagent_registration * __single search_netagent = NULL;
2559 
2560 	response_size = buffer_length; // We already know that buffer_length is the same as total_netagent_data_size.
2561 	cursor = buffer;
2562 	LIST_FOREACH(search_netagent, &shared_netagent_list, global_chain) {
2563 		memcpy(cursor, search_netagent->netagent->netagent_uuid, sizeof(search_netagent->netagent->netagent_uuid));
2564 		cursor += sizeof(search_netagent->netagent->netagent_uuid);
2565 	}
2566 }
2567 
2568 int
netagent_ioctl(u_long cmd,caddr_t __sized_by (IOCPARM_LEN (cmd))data)2569 netagent_ioctl(u_long cmd, caddr_t __sized_by(IOCPARM_LEN(cmd)) data)
2570 {
2571 	int error = 0;
2572 
2573 	switch (cmd) {
2574 	case SIOCGIFAGENTLIST32:
2575 	case SIOCGIFAGENTLIST64: {
2576 		/* Check entitlement if the client requests agent dump */
2577 		errno_t cred_result = priv_check_cred(kauth_cred_get(), PRIV_NET_PRIVILEGED_NECP_POLICIES, 0);
2578 		if (cred_result != 0) {
2579 			NETAGENTLOG0(LOG_ERR, "Client does not hold the necessary entitlement to get netagent information");
2580 			return EINVAL;
2581 		}
2582 		break;
2583 	}
2584 	default:
2585 		break;
2586 	}
2587 
2588 	NETAGENT_LIST_LOCK_SHARED();
2589 	switch (cmd) {
2590 	case SIOCGIFAGENTDATA32: {
2591 		struct netagent_req32 *ifsir32 = (struct netagent_req32 *)(void *)data;
2592 		struct netagent_registration *registration = netagent_find_agent_with_uuid_and_lock(ifsir32->netagent_uuid, false, false);
2593 		if (registration == NULL) {
2594 			error = ENOENT;
2595 			break;
2596 		}
2597 		uuid_copy(ifsir32->netagent_uuid, registration->netagent->netagent_uuid);
2598 		memcpy(ifsir32->netagent_domain, registration->netagent->netagent_domain, sizeof(ifsir32->netagent_domain));
2599 		memcpy(ifsir32->netagent_type, registration->netagent->netagent_type, sizeof(ifsir32->netagent_type));
2600 		memcpy(ifsir32->netagent_desc, registration->netagent->netagent_desc, sizeof(ifsir32->netagent_desc));
2601 		ifsir32->netagent_flags = registration->netagent->netagent_flags;
2602 		if (ifsir32->netagent_data_size == 0) {
2603 			// First pass, client wants data size
2604 			ifsir32->netagent_data_size = registration->netagent->netagent_data_size;
2605 		} else if (ifsir32->netagent_data != USER_ADDR_NULL &&
2606 		    ifsir32->netagent_data_size == registration->netagent->netagent_data_size) {
2607 			// Second pass, client wants data buffer filled out
2608 			error = copyout(netagent_get_data(registration->netagent), ifsir32->netagent_data, registration->netagent->netagent_data_size);
2609 		} else {
2610 			error = EINVAL;
2611 		}
2612 		NETAGENT_UNLOCK(registration);
2613 		break;
2614 	}
2615 	case SIOCGIFAGENTDATA64: {
2616 		struct netagent_req64 *ifsir64 = (struct netagent_req64 *)(void *)data;
2617 		struct netagent_registration *registration = netagent_find_agent_with_uuid_and_lock(ifsir64->netagent_uuid, false, false);
2618 		if (registration == NULL) {
2619 			error = ENOENT;
2620 			break;
2621 		}
2622 		uuid_copy(ifsir64->netagent_uuid, registration->netagent->netagent_uuid);
2623 		memcpy(ifsir64->netagent_domain, registration->netagent->netagent_domain, sizeof(ifsir64->netagent_domain));
2624 		memcpy(ifsir64->netagent_type, registration->netagent->netagent_type, sizeof(ifsir64->netagent_type));
2625 		memcpy(ifsir64->netagent_desc, registration->netagent->netagent_desc, sizeof(ifsir64->netagent_desc));
2626 		ifsir64->netagent_flags = registration->netagent->netagent_flags;
2627 		if (ifsir64->netagent_data_size == 0) {
2628 			// First pass, client wants data size
2629 			ifsir64->netagent_data_size = registration->netagent->netagent_data_size;
2630 		} else if (ifsir64->netagent_data != USER_ADDR_NULL &&
2631 		    ifsir64->netagent_data_size == registration->netagent->netagent_data_size) {
2632 			// Second pass, client wants data buffer filled out
2633 			error = copyout(netagent_get_data(registration->netagent), ifsir64->netagent_data, registration->netagent->netagent_data_size);
2634 		} else {
2635 			error = EINVAL;
2636 		}
2637 		NETAGENT_UNLOCK(registration);
2638 		break;
2639 	}
2640 	case SIOCGIFAGENTLIST32: {
2641 		struct netagentlist_req32 *ifsir32 = (struct netagentlist_req32 *)(void *)data;
2642 		if (ifsir32->data_size == 0) {
2643 			// First pass, client wants data size
2644 			ifsir32->data_size = netagent_dump_get_data_size_locked();
2645 		} else if (ifsir32->data != USER_ADDR_NULL &&
2646 		    ifsir32->data_size > 0 &&
2647 		    ifsir32->data_size == netagent_dump_get_data_size_locked()) {
2648 			// Second pass, client wants data buffer filled out
2649 			u_int8_t *response = NULL;
2650 			response = (u_int8_t *)kalloc_data(ifsir32->data_size, Z_NOWAIT | Z_ZERO);
2651 			if (response == NULL) {
2652 				error = ENOMEM;
2653 				break;
2654 			}
2655 
2656 			netagent_dump_copy_data_locked(response, ifsir32->data_size);
2657 			error = copyout(response, ifsir32->data, ifsir32->data_size);
2658 			kfree_data(response, ifsir32->data_size);
2659 		} else {
2660 			error = EINVAL;
2661 		}
2662 		break;
2663 	}
2664 	case SIOCGIFAGENTLIST64: {
2665 		struct netagentlist_req64 *ifsir64 = (struct netagentlist_req64 *)(void *)data;
2666 		if (ifsir64->data_size == 0) {
2667 			// First pass, client wants data size
2668 			ifsir64->data_size = netagent_dump_get_data_size_locked();
2669 		} else if (ifsir64->data != USER_ADDR_NULL &&
2670 		    ifsir64->data_size > 0 &&
2671 		    ifsir64->data_size == netagent_dump_get_data_size_locked()) {
2672 			// Second pass, client wants data buffer filled out
2673 			u_int8_t *response = NULL;
2674 			response = (u_int8_t *)kalloc_data(ifsir64->data_size, Z_NOWAIT | Z_ZERO);
2675 			if (response == NULL) {
2676 				error = ENOMEM;
2677 				break;
2678 			}
2679 
2680 			netagent_dump_copy_data_locked(response, ifsir64->data_size);
2681 			error = copyout(response, ifsir64->data, ifsir64->data_size);
2682 			kfree_data(response, ifsir64->data_size);
2683 		} else {
2684 			error = EINVAL;
2685 		}
2686 		break;
2687 	}
2688 	default: {
2689 		error = EINVAL;
2690 		break;
2691 	}
2692 	}
2693 	NETAGENT_LIST_UNLOCK();
2694 	return error;
2695 }
2696 
2697 u_int32_t
netagent_get_flags(uuid_t uuid)2698 netagent_get_flags(uuid_t uuid)
2699 {
2700 	u_int32_t flags = 0;
2701 	NETAGENT_LIST_LOCK_SHARED();
2702 	struct netagent_registration *registration = netagent_find_agent_with_uuid_and_lock(uuid, false, false);
2703 	if (registration != NULL) {
2704 		flags = registration->netagent->netagent_flags;
2705 		NETAGENT_UNLOCK(registration);
2706 	} else {
2707 		NETAGENTLOG0(LOG_DEBUG, "Flags requested for invalid netagent");
2708 	}
2709 	NETAGENT_LIST_UNLOCK();
2710 
2711 	return flags;
2712 }
2713 
2714 errno_t
netagent_set_flags(uuid_t uuid,u_int32_t flags)2715 netagent_set_flags(uuid_t uuid, u_int32_t flags)
2716 {
2717 	errno_t error = 0;
2718 	bool updated = false;
2719 
2720 	NETAGENT_LIST_LOCK_SHARED();
2721 	struct netagent_registration *registration = netagent_find_agent_with_uuid_and_lock(uuid, true, false);
2722 	if (registration != NULL) {
2723 		// Don't allow the clients to clear
2724 		// NETAGENT_FLAG_REGISTERED.
2725 		uint32_t registered =
2726 		    registration->netagent->netagent_flags & NETAGENT_FLAG_REGISTERED;
2727 		flags |= registered;
2728 		if (registration->netagent->netagent_flags != flags) {
2729 			registration->netagent->netagent_flags = flags;
2730 			registration->generation = g_next_generation++;
2731 			updated = true;
2732 		}
2733 		NETAGENT_UNLOCK(registration);
2734 	} else {
2735 		NETAGENTLOG0(LOG_DEBUG,
2736 		    "Attempt to set flags for invalid netagent");
2737 		error = ENOENT;
2738 	}
2739 	NETAGENT_LIST_UNLOCK();
2740 	if (updated) {
2741 		netagent_post_event(uuid, KEV_NETAGENT_UPDATED, true, false);
2742 	}
2743 
2744 	return error;
2745 }
2746 
2747 u_int32_t
netagent_get_generation(uuid_t uuid)2748 netagent_get_generation(uuid_t uuid)
2749 {
2750 	u_int32_t generation = 0;
2751 	NETAGENT_LIST_LOCK_SHARED();
2752 	struct netagent_registration *registration = netagent_find_agent_with_uuid_and_lock(uuid, false, false);
2753 	if (registration != NULL) {
2754 		generation = registration->generation;
2755 		NETAGENT_UNLOCK(registration);
2756 	} else {
2757 		NETAGENTLOG0(LOG_DEBUG, "Generation requested for invalid netagent");
2758 	}
2759 	NETAGENT_LIST_UNLOCK();
2760 
2761 	return generation;
2762 }
2763 
2764 bool
netagent_get_agent_domain_and_type(uuid_t uuid,char * __sized_by (NETAGENT_DOMAINSIZE)domain,char * __sized_by (NETAGENT_TYPESIZE)type)2765 netagent_get_agent_domain_and_type(uuid_t uuid, char * __sized_by(NETAGENT_DOMAINSIZE)domain, char * __sized_by(NETAGENT_TYPESIZE)type)
2766 {
2767 	bool found = FALSE;
2768 	if (domain == NULL || type == NULL) {
2769 		NETAGENTLOG(LOG_ERR, "Invalid arguments for netagent_get_agent_domain_and_type %p %p", domain, type);
2770 		return FALSE;
2771 	}
2772 
2773 	NETAGENT_LIST_LOCK_SHARED();
2774 	struct netagent_registration *registration = netagent_find_agent_with_uuid_and_lock(uuid, false, false);
2775 	if (registration != NULL) {
2776 		found = TRUE;
2777 		memcpy(domain, registration->netagent->netagent_domain, NETAGENT_DOMAINSIZE);
2778 		memcpy(type, registration->netagent->netagent_type, NETAGENT_TYPESIZE);
2779 		NETAGENT_UNLOCK(registration);
2780 	} else {
2781 		NETAGENTLOG0(LOG_ERR, "Type requested for invalid netagent");
2782 	}
2783 	NETAGENT_LIST_UNLOCK();
2784 
2785 	return found;
2786 }
2787 
2788 int
netagent_kernel_trigger(uuid_t uuid)2789 netagent_kernel_trigger(uuid_t uuid)
2790 {
2791 	int error = 0;
2792 
2793 	NETAGENT_LIST_LOCK_SHARED();
2794 	struct netagent_registration *registration = netagent_find_agent_with_uuid_and_lock(uuid, false, false);
2795 	if (registration == NULL) {
2796 		NETAGENTLOG0(LOG_ERR, "Requested netagent for kernel trigger could not be found");
2797 		error = ENOENT;
2798 		goto done;
2799 	}
2800 
2801 	if ((registration->netagent->netagent_flags & NETAGENT_FLAG_KERNEL_ACTIVATED) == 0) {
2802 		NETAGENTLOG0(LOG_ERR, "Requested netagent for kernel trigger is not kernel activated");
2803 		// Agent does not accept kernel triggers
2804 		error = EINVAL;
2805 		goto done;
2806 	}
2807 
2808 	if ((registration->netagent->netagent_flags & NETAGENT_FLAG_ACTIVE)) {
2809 		// Agent already active
2810 		NETAGENTLOG0(LOG_INFO, "Requested netagent for kernel trigger is already active");
2811 		error = 0;
2812 		goto done;
2813 	}
2814 
2815 	error = netagent_send_trigger(registration, current_proc(), NETAGENT_TRIGGER_FLAG_KERNEL, NETAGENT_MESSAGE_TYPE_TRIGGER);
2816 	NETAGENTLOG((error ? LOG_ERR : LOG_INFO), "Triggered netagent from kernel (error %d)", error);
2817 done:
2818 	if (registration != NULL) {
2819 		NETAGENT_UNLOCK(registration);
2820 	}
2821 	NETAGENT_LIST_UNLOCK();
2822 	return error;
2823 }
2824 
2825 int
netagent_client_message_with_params(uuid_t agent_uuid,uuid_t necp_client_uuid,pid_t pid,void * handle,u_int8_t message_type,struct necp_client_agent_parameters * parameters,void * __sized_by (* assigned_results_length)* assigned_results,size_t * assigned_results_length)2826 netagent_client_message_with_params(uuid_t agent_uuid,
2827     uuid_t necp_client_uuid,
2828     pid_t pid,
2829     void *handle,
2830     u_int8_t message_type,
2831     struct necp_client_agent_parameters *parameters,
2832     void * __sized_by(*assigned_results_length) *assigned_results,
2833     size_t *assigned_results_length)
2834 {
2835 	int error = 0;
2836 
2837 	if (message_type != NETAGENT_MESSAGE_TYPE_CLIENT_TRIGGER &&
2838 	    message_type != NETAGENT_MESSAGE_TYPE_CLIENT_ASSERT &&
2839 	    message_type != NETAGENT_MESSAGE_TYPE_CLIENT_UNASSERT &&
2840 	    message_type != NETAGENT_MESSAGE_TYPE_CLIENT_ERROR &&
2841 	    message_type != NETAGENT_MESSAGE_TYPE_REQUEST_NEXUS &&
2842 	    message_type != NETAGENT_MESSAGE_TYPE_CLOSE_NEXUS &&
2843 	    message_type != NETAGENT_MESSAGE_TYPE_ABORT_NEXUS &&
2844 	    message_type != NETAGENT_MESSAGE_TYPE_ADD_GROUP_MEMBERS &&
2845 	    message_type != NETAGENT_MESSAGE_TYPE_REMOVE_GROUP_MEMBERS) {
2846 		NETAGENTLOG(LOG_ERR, "Client netagent message type (%d) is invalid", message_type);
2847 		return EINVAL;
2848 	}
2849 
2850 	NETAGENT_LIST_LOCK_SHARED();
2851 	bool should_unlock_list = true;
2852 	bool should_unlock_registration = true;
2853 	struct netagent_registration *registration = netagent_find_agent_with_uuid_and_lock(agent_uuid, false, false);
2854 	if (registration == NULL) {
2855 		NETAGENTLOG0(LOG_DEBUG, "Requested netagent for nexus instance could not be found");
2856 		error = ENOENT;
2857 		goto done;
2858 	}
2859 
2860 	if (message_type == NETAGENT_MESSAGE_TYPE_CLIENT_TRIGGER) {
2861 		if ((registration->netagent->netagent_flags & NETAGENT_FLAG_USER_ACTIVATED) == 0) {
2862 			// Agent does not accept user triggers
2863 			// Don't log, since this is a common case used to trigger events that cellular data is blocked, etc.
2864 			error = ENOTSUP;
2865 
2866 
2867 			pid_t report_pid = 0;
2868 			uuid_t report_proc_uuid = {};
2869 			if (parameters != NULL) {
2870 				report_pid = parameters->u.nexus_request.epid;
2871 				uuid_copy(report_proc_uuid, parameters->u.nexus_request.euuid);
2872 			} else {
2873 				struct proc *p = current_proc();
2874 				if (p != NULL) {
2875 					report_pid = proc_pid(p);
2876 					proc_getexecutableuuid(p, report_proc_uuid, sizeof(report_proc_uuid));
2877 				}
2878 			}
2879 			netagent_send_cellular_failed_event(registration, report_pid, report_proc_uuid);
2880 			goto done;
2881 		}
2882 	} else if (message_type == NETAGENT_MESSAGE_TYPE_REQUEST_NEXUS ||
2883 	    message_type == NETAGENT_MESSAGE_TYPE_CLOSE_NEXUS ||
2884 	    message_type == NETAGENT_MESSAGE_TYPE_ABORT_NEXUS) {
2885 		bool is_nexus_agent = ((registration->netagent->netagent_flags &
2886 		    (NETAGENT_FLAG_NEXUS_PROVIDER |
2887 		    NETAGENT_FLAG_NEXUS_LISTENER |
2888 		    NETAGENT_FLAG_CUSTOM_IP_NEXUS |
2889 		    NETAGENT_FLAG_CUSTOM_ETHER_NEXUS |
2890 		    NETAGENT_FLAG_INTERPOSE_NEXUS)) != 0);
2891 		if (!is_nexus_agent) {
2892 			NETAGENTLOG0(LOG_ERR, "Requested netagent for nexus instance is not a nexus provider");
2893 			// Agent is not a nexus provider
2894 			error = EINVAL;
2895 			goto done;
2896 		}
2897 
2898 		if ((registration->netagent->netagent_flags & NETAGENT_FLAG_ACTIVE) == 0) {
2899 			// Agent not active
2900 			NETAGENTLOG0(LOG_INFO, "Requested netagent for nexus instance is not active");
2901 			error = EINVAL;
2902 			goto done;
2903 		}
2904 	} else if (message_type == NETAGENT_MESSAGE_TYPE_ADD_GROUP_MEMBERS ||
2905 	    message_type == NETAGENT_MESSAGE_TYPE_REMOVE_GROUP_MEMBERS) {
2906 		bool is_group_agent = ((registration->netagent->netagent_flags & (NETAGENT_FLAG_SUPPORTS_GROUPS)) != 0);
2907 		if (!is_group_agent) {
2908 			NETAGENTLOG0(LOG_ERR, "Requested netagent for group operation is not a group provider");
2909 			error = EINVAL;
2910 			goto done;
2911 		}
2912 
2913 		if ((registration->netagent->netagent_flags & NETAGENT_FLAG_ACTIVE) == 0) {
2914 			// Agent not active
2915 			NETAGENTLOG0(LOG_INFO, "Requested netagent for group operation is not active");
2916 			error = EINVAL;
2917 			goto done;
2918 		}
2919 	}
2920 
2921 	if (registration->control_unit == 0) {
2922 		if (registration->event_handler == NULL) {
2923 			// No event handler registered for kernel agent
2924 			error = EINVAL;
2925 		} else {
2926 			// We hold the registration lock during the event handler callout, so it is expected
2927 			// that the event handler will not lead to any registrations or unregistrations
2928 			// of network agents.
2929 			// We release the list lock before calling the event handler to allow other threads
2930 			// to access the list while the event is processing.
2931 			NETAGENT_LIST_UNLOCK();
2932 			should_unlock_list = false;
2933 			error = registration->event_handler(message_type, necp_client_uuid, pid, handle,
2934 			    registration->event_context, parameters,
2935 			    assigned_results, assigned_results_length);
2936 			if (error != 0) {
2937 				VERIFY(assigned_results == NULL || *assigned_results == NULL);
2938 				VERIFY(assigned_results_length == NULL || *assigned_results_length == 0);
2939 			}
2940 		}
2941 	} else {
2942 		// ABORT_NEXUS is kernel-private, so translate it for userspace nexus
2943 		if (message_type == NETAGENT_MESSAGE_TYPE_ABORT_NEXUS) {
2944 			message_type = NETAGENT_MESSAGE_TYPE_CLOSE_NEXUS;
2945 		}
2946 
2947 		if (message_type == NETAGENT_MESSAGE_TYPE_CLIENT_ERROR) {
2948 			const int32_t client_error = parameters->u.error.error;
2949 			const bool force_report = parameters->u.error.force_report;
2950 			if (registration->last_client_error != client_error || // Always notify for an error change
2951 			    force_report || // Always notify if force reporting was requested
2952 			    (client_error == 0 && registration->client_error_count == 0) || // Only notify once for no-error
2953 			    (client_error != 0 && registration->client_error_count < NETAGENT_MAX_CLIENT_ERROR_COUNT)) {
2954 				if (NETAGENT_LOCK_SHARED_TO_EXCLUSIVE(registration)) {
2955 					if (registration->last_client_error != client_error) {
2956 						registration->last_client_error = client_error;
2957 						registration->client_error_count = 1;
2958 					} else {
2959 						registration->client_error_count++;
2960 					}
2961 					error = netagent_send_error_message(registration, necp_client_uuid, message_type, client_error);
2962 				} else {
2963 					// If NETAGENT_LOCK_SHARED_TO_EXCLUSIVE fails, it unlocks automatically
2964 					should_unlock_registration = false;
2965 				}
2966 			}
2967 		} else if (message_type == NETAGENT_MESSAGE_TYPE_ADD_GROUP_MEMBERS ||
2968 		    message_type == NETAGENT_MESSAGE_TYPE_REMOVE_GROUP_MEMBERS) {
2969 			error = netagent_send_group_message(registration, necp_client_uuid, message_type, &parameters->u.group_members);
2970 		} else {
2971 			error = netagent_send_client_message(registration, necp_client_uuid, message_type);
2972 		}
2973 		if (error == 0 && message_type == NETAGENT_MESSAGE_TYPE_CLIENT_TRIGGER) {
2974 			if (NETAGENT_LOCK_SHARED_TO_EXCLUSIVE(registration)) {
2975 				// Grab the lock exclusively to add a pending client to the list
2976 				struct netagent_client *new_pending_client = NULL;
2977 				new_pending_client = kalloc_type(struct netagent_client, Z_WAITOK);
2978 				if (new_pending_client == NULL) {
2979 					NETAGENTLOG0(LOG_ERR, "Failed to allocate client for trigger");
2980 				} else {
2981 					uuid_copy(new_pending_client->client_id, necp_client_uuid);
2982 					if (parameters != NULL) {
2983 						new_pending_client->client_pid = parameters->u.nexus_request.epid;
2984 						uuid_copy(new_pending_client->client_proc_uuid, parameters->u.nexus_request.euuid);
2985 					} else {
2986 						struct proc *p = current_proc();
2987 						if (p != NULL) {
2988 							new_pending_client->client_pid = proc_pid(p);
2989 							proc_getexecutableuuid(p, new_pending_client->client_proc_uuid, sizeof(new_pending_client->client_proc_uuid));
2990 						}
2991 					}
2992 					LIST_INSERT_HEAD(&registration->pending_triggers_list, new_pending_client, client_chain);
2993 				}
2994 			} else {
2995 				// If NETAGENT_LOCK_SHARED_TO_EXCLUSIVE fails, it unlocks automatically
2996 				should_unlock_registration = false;
2997 			}
2998 		}
2999 	}
3000 	NETAGENTLOG(((error && error != ENOENT) ? LOG_ERR : LOG_INFO), "Send message %d for client (error %d)", message_type, error);
3001 	if (message_type == NETAGENT_MESSAGE_TYPE_CLIENT_TRIGGER) {
3002 		uuid_string_t uuid_str;
3003 		uuid_unparse(agent_uuid, uuid_str);
3004 		NETAGENTLOG(LOG_NOTICE, "Triggered network agent %s, error = %d", uuid_str, error);
3005 	}
3006 done:
3007 	if (should_unlock_registration && registration != NULL) {
3008 		NETAGENT_UNLOCK(registration);
3009 	}
3010 	if (should_unlock_list) {
3011 		NETAGENT_LIST_UNLOCK();
3012 	}
3013 	return error;
3014 }
3015 
3016 int
netagent_client_message(uuid_t agent_uuid,uuid_t necp_client_uuid,pid_t pid,void * handle,u_int8_t message_type)3017 netagent_client_message(uuid_t agent_uuid, uuid_t necp_client_uuid, pid_t pid, void *handle, u_int8_t message_type)
3018 {
3019 	size_t dummy_length = 0;
3020 	void *dummy_results __sized_by(dummy_length) = NULL;
3021 
3022 	return netagent_client_message_with_params(agent_uuid, necp_client_uuid, pid, handle, message_type, NULL, &dummy_results, &dummy_length);
3023 }
3024 
3025 int
netagent_use(uuid_t agent_uuid,uint64_t * out_use_count)3026 netagent_use(uuid_t agent_uuid, uint64_t *out_use_count)
3027 {
3028 	int error = 0;
3029 
3030 	NETAGENT_LIST_LOCK_SHARED();
3031 	struct netagent_registration *registration = netagent_find_agent_with_uuid_and_lock(agent_uuid, true, false);
3032 	if (registration == NULL) {
3033 		NETAGENTLOG0(LOG_ERR, "netagent_assert: Requested netagent UUID is not registered");
3034 		error = ENOENT;
3035 		goto done;
3036 	}
3037 
3038 	uint64_t current_count = registration->use_count;
3039 	registration->use_count++;
3040 
3041 	if (out_use_count != NULL) {
3042 		*out_use_count = current_count;
3043 	}
3044 
3045 done:
3046 	if (registration != NULL) {
3047 		NETAGENT_UNLOCK(registration);
3048 	}
3049 	NETAGENT_LIST_UNLOCK();
3050 	return error;
3051 }
3052 
3053 int
netagent_copyout(uuid_t agent_uuid,user_addr_t user_addr,u_int32_t user_size)3054 netagent_copyout(uuid_t agent_uuid, user_addr_t user_addr, u_int32_t user_size)
3055 {
3056 	int error = 0;
3057 
3058 	NETAGENT_LIST_LOCK_SHARED();
3059 	struct netagent_registration *registration = netagent_find_agent_with_uuid_and_lock(agent_uuid, false, false);
3060 	if (registration == NULL) {
3061 		NETAGENTLOG0(LOG_DEBUG, "Requested netagent for nexus instance could not be found");
3062 		error = ENOENT;
3063 		goto done;
3064 	}
3065 
3066 	u_int32_t total_size = (sizeof(struct netagent) + registration->netagent->netagent_data_size);
3067 	if (user_size < total_size) {
3068 		NETAGENTLOG(LOG_ERR, "Provided user buffer is too small (%u < %u)", user_size, total_size);
3069 		error = EINVAL;
3070 		goto done;
3071 	}
3072 
3073 	u_int8_t *ptr = __unsafe_forge_bidi_indexable(u_int8_t *, registration->netagent, total_size);
3074 	error = copyout(ptr, user_addr, total_size);
3075 
3076 	NETAGENTLOG((error ? LOG_ERR : LOG_DEBUG), "Copied agent content (error %d)", error);
3077 done:
3078 	if (registration != NULL) {
3079 		NETAGENT_UNLOCK(registration);
3080 	}
3081 	NETAGENT_LIST_UNLOCK();
3082 	return error;
3083 }
3084 
3085 #define NETAGENT_TOKEN_EVENT_INTERVAL_NSEC (NSEC_PER_SEC * 10) // Only fire repeated events up to once every 10 seconds
3086 
3087 int
netagent_acquire_token(uuid_t agent_uuid,user_addr_t user_addr,u_int32_t user_size,int * retval)3088 netagent_acquire_token(uuid_t agent_uuid, user_addr_t user_addr, u_int32_t user_size, int *retval)
3089 {
3090 	int error = 0;
3091 
3092 	NETAGENT_LIST_LOCK_SHARED();
3093 	struct netagent_registration *registration = netagent_find_agent_with_uuid_and_lock(agent_uuid, true, false);
3094 	if (registration == NULL) {
3095 		NETAGENTLOG0(LOG_DEBUG, "Network agent for request UUID could not be found");
3096 		error = ENOENT;
3097 		goto done;
3098 	}
3099 
3100 	struct netagent_token *token = TAILQ_FIRST(&registration->token_list);
3101 	if (token == NULL) {
3102 		NETAGENTLOG0(LOG_DEBUG, "Network agent does not have any tokens");
3103 		if (registration->token_low_water != 0) {
3104 			// Only fire an event if one hasn't occurred in the last 10 seconds
3105 			if (mach_absolute_time() >= registration->need_tokens_event_deadline) {
3106 				int event_error = netagent_send_tokens_needed(registration);
3107 				if (event_error == 0) {
3108 					// Reset the deadline
3109 					uint64_t deadline = 0;
3110 					nanoseconds_to_absolutetime(NETAGENT_TOKEN_EVENT_INTERVAL_NSEC, &deadline);
3111 					clock_absolutetime_interval_to_deadline(deadline, &deadline);
3112 					registration->need_tokens_event_deadline = deadline;
3113 				}
3114 			}
3115 		}
3116 		error = ENODATA;
3117 		goto done;
3118 	}
3119 
3120 	if (user_size < token->token_length) {
3121 		NETAGENTLOG(LOG_ERR, "Provided user buffer is too small (%u < %u)", user_size, token->token_length);
3122 		error = EMSGSIZE;
3123 		goto done;
3124 	}
3125 
3126 	error = copyout(token->token_bytes, user_addr, token->token_length);
3127 	if (error == 0) {
3128 		*retval = (int)token->token_length;
3129 	}
3130 
3131 	NETAGENTLOG((error ? LOG_ERR : LOG_DEBUG), "Copied token content (error %d)", error);
3132 
3133 	TAILQ_REMOVE(&registration->token_list, token, token_chain);
3134 	netagent_token_free(token);
3135 	if (registration->token_count > 0) {
3136 		registration->token_count--;
3137 	}
3138 	if (registration->token_count < registration->token_low_water) {
3139 		(void)netagent_send_tokens_needed(registration);
3140 	}
3141 done:
3142 	if (registration != NULL) {
3143 		NETAGENT_UNLOCK(registration);
3144 	}
3145 	NETAGENT_LIST_UNLOCK();
3146 	return error;
3147 }
3148 
3149 int
netagent_trigger(struct proc * p,struct netagent_trigger_args * uap,int32_t * retval)3150 netagent_trigger(struct proc *p, struct netagent_trigger_args *uap, int32_t *retval)
3151 {
3152 #pragma unused(p, retval)
3153 	uuid_t agent_uuid = {};
3154 	int error = 0;
3155 
3156 	if (uap == NULL) {
3157 		NETAGENTLOG0(LOG_ERR, "uap == NULL");
3158 		return EINVAL;
3159 	}
3160 
3161 	if (uap->agent_uuid) {
3162 		if (uap->agent_uuidlen != sizeof(uuid_t)) {
3163 			NETAGENTLOG(LOG_ERR, "Incorrect length (got %zu, expected %lu)",
3164 			    (size_t)uap->agent_uuidlen, sizeof(uuid_t));
3165 			return ERANGE;
3166 		}
3167 
3168 		error = copyin(uap->agent_uuid, agent_uuid, sizeof(uuid_t));
3169 		if (error) {
3170 			NETAGENTLOG(LOG_ERR, "copyin error (%d)", error);
3171 			return error;
3172 		}
3173 	}
3174 
3175 	if (uuid_is_null(agent_uuid)) {
3176 		NETAGENTLOG0(LOG_ERR, "Requested netagent UUID is empty");
3177 		return EINVAL;
3178 	}
3179 
3180 	NETAGENT_LIST_LOCK_SHARED();
3181 	struct netagent_registration *registration = netagent_find_agent_with_uuid_and_lock(agent_uuid, false, false);
3182 	if (registration == NULL) {
3183 		NETAGENTLOG0(LOG_ERR, "Requested netagent UUID is not registered");
3184 		error = ENOENT;
3185 		goto done;
3186 	}
3187 
3188 	if ((registration->netagent->netagent_flags & NETAGENT_FLAG_USER_ACTIVATED) == 0) {
3189 		// Agent does not accept triggers
3190 		NETAGENTLOG0(LOG_ERR, "Requested netagent UUID is not eligible for triggering");
3191 		error = ENOTSUP;
3192 		goto done;
3193 	}
3194 
3195 	if ((registration->netagent->netagent_flags & NETAGENT_FLAG_ACTIVE)) {
3196 		// Agent already active
3197 		NETAGENTLOG0(LOG_INFO, "Requested netagent UUID is already active");
3198 		error = 0;
3199 		goto done;
3200 	}
3201 
3202 	error = netagent_send_trigger(registration, p, NETAGENT_TRIGGER_FLAG_USER, NETAGENT_MESSAGE_TYPE_TRIGGER);
3203 	NETAGENTLOG((error ? LOG_ERR : LOG_INFO), "Triggered netagent (error %d)", error);
3204 done:
3205 	if (registration != NULL) {
3206 		NETAGENT_UNLOCK(registration);
3207 	}
3208 	NETAGENT_LIST_UNLOCK();
3209 	return error;
3210 }
3211