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