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