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
48u_int32_t netagent_debug = LOG_NOTICE; // 0=None, 1=Basic
49
50SYSCTL_NODE(_net, OID_AUTO, netagent, CTLFLAG_RW | CTLFLAG_LOCKED, 0, "NetworkAgent");
51SYSCTL_INT(_net_netagent, OID_AUTO, debug, CTLFLAG_LOCKED | CTLFLAG_RW, &netagent_debug, 0, "");
52
53static int netagent_registered_count = 0;
54SYSCTL_INT(_net_netagent, OID_AUTO, registered_count, CTLFLAG_RD | CTLFLAG_LOCKED,
55 &netagent_registered_count, 0, "");
56
57static int netagent_active_count = 0;
58SYSCTL_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
81struct 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
88LIST_HEAD(netagent_client_list_s, netagent_client);
89
90struct netagent_token {
91 TAILQ_ENTRY(netagent_token) token_chain;
92 u_int32_t token_length;
93 u_int8_t *token_bytes;
94};
95
96TAILQ_HEAD(netagent_token_list_s, netagent_token);
97
98#define NETAGENT_MAX_CLIENT_ERROR_COUNT 32
99
100struct 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
119struct 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
127typedef enum {
128 kNetagentErrorDomainPOSIX = 0,
129 kNetagentErrorDomainUserDefined = 1,
130} netagent_error_domain_t;
131
132static LIST_HEAD(_netagent_list, netagent_wrapper) shared_netagent_list =
133 LIST_HEAD_INITIALIZER(master_netagent_list);
134
135// Protected by netagent_list_lock
136static u_int32_t g_next_generation = 1;
137
138static kern_ctl_ref netagent_kctlref;
139static u_int32_t netagent_family;
140static LCK_GRP_DECLARE(netagent_mtx_grp, NETAGENT_CONTROL_NAME);
141static 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
164static errno_t netagent_register_control(void);
165static errno_t netagent_ctl_connect(kern_ctl_ref kctlref, struct sockaddr_ctl *sac,
166 void **unitinfo);
167static errno_t netagent_ctl_disconnect(kern_ctl_ref kctlref, u_int32_t unit, void *unitinfo);
168static errno_t netagent_ctl_send(kern_ctl_ref kctlref, u_int32_t unit, void *unitinfo,
169 mbuf_t m, int flags);
170static void netagent_ctl_rcvd(kern_ctl_ref kctlref, u_int32_t unit, void *unitinfo, int flags);
171static errno_t netagent_ctl_getopt(kern_ctl_ref kctlref, u_int32_t unit, void *unitinfo,
172 int opt, void *data, size_t *len);
173static errno_t netagent_ctl_setopt(kern_ctl_ref kctlref, u_int32_t unit, void *unitinfo,
174 int opt, void *data, size_t len);
175
176static int netagent_send_ctl_data(u_int32_t control_unit, u_int8_t *buffer, size_t buffer_size);
177
178static struct netagent_session *netagent_create_session(u_int32_t control_unit);
179static void netagent_delete_session(struct netagent_session *session);
180
181// Register
182static 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);
184static errno_t netagent_handle_register_setopt(struct netagent_session *session, u_int8_t *payload,
185 size_t payload_length);
186
187// Unregister
188static 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);
190static errno_t netagent_handle_unregister_setopt(struct netagent_session *session, u_int8_t *payload,
191 size_t payload_length);
192
193// Update
194static 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);
196static errno_t netagent_handle_update_setopt(struct netagent_session *session, u_int8_t *payload,
197 size_t payload_length);
198
199// Assign nexus
200static 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);
202static errno_t netagent_handle_assign_nexus_setopt(struct netagent_session *session, u_int8_t *payload,
203 size_t payload_length);
204
205// Assign group
206static 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
210static errno_t netagent_handle_use_count_setopt(struct netagent_session *session, u_int8_t *payload, size_t payload_length);
211static errno_t netagent_handle_use_count_getopt(struct netagent_session *session, u_int8_t *buffer, size_t *buffer_length);
212
213// Manage tokens
214static errno_t netagent_handle_add_token_setopt(struct netagent_session *session, u_int8_t *payload, size_t payload_length);
215static errno_t netagent_handle_flush_tokens_setopt(struct netagent_session *session, u_int8_t *payload, size_t payload_length);
216static errno_t netagent_handle_token_count_getopt(struct netagent_session *session, u_int8_t *buffer, size_t *buffer_length);
217static errno_t netagent_handle_token_low_water_setopt(struct netagent_session *session, u_int8_t *buffer, size_t buffer_length);
218static errno_t netagent_handle_token_low_water_getopt(struct netagent_session *session, u_int8_t *buffer, size_t *buffer_length);
219
220// Client error
221static errno_t netagent_handle_reset_client_error_setopt(struct netagent_session *session, u_int8_t *payload, size_t payload_length);
222
223static 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
227static struct netagent_wrapper *netagent_find_agent_with_uuid_and_lock(uuid_t uuid, bool exclusively, bool ignore_lock);
228
229errno_t
230netagent_init(void)
231{
232 return netagent_register_control();
233}
234
235static errno_t
236netagent_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, module_id: &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(s: &kern_ctl, n: sizeof(kern_ctl));
249 strlcpy(dst: kern_ctl.ctl_name, NETAGENT_CONTROL_NAME, n: 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(userkctl: &kern_ctl, kctlref: &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
270static errno_t
271netagent_ctl_connect(kern_ctl_ref kctlref, struct sockaddr_ctl *sac, void **unitinfo)
272{
273#pragma unused(kctlref)
274 *unitinfo = netagent_create_session(control_unit: sac->sc_unit);
275 if (*unitinfo == NULL) {
276 // Could not allocate session
277 return ENOBUFS;
278 }
279
280 return 0;
281}
282
283static errno_t
284netagent_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
296static void
297netagent_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(s: &ev_msg, c: 0, n: 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(dst: event_data.netagent_uuid, src: 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(event: &ev_msg);
318}
319
320// Message handling
321static u_int8_t *
322netagent_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(s: buffer, c: 0, n: 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
334static int
335netagent_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(kctlref: netagent_kctlref, unit: control_unit, data: buffer, len: buffer_size, CTL_DATA_EOR);
342}
343
344static int
345netagent_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(buffer: trigger, message_type: trigger_type, flags: 0, message_id: 0, error: 0, payload_length: 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(uu: trigger_message->trigger_proc_uuid);
367 }
368
369 if ((error = netagent_send_ctl_data(control_unit: wrapper->control_unit, buffer: trigger, buffer_size: 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
377static int
378netagent_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(buffer: message, message_type, flags: 0, message_id: 0, error: 0, payload_length: sizeof(struct netagent_client_message));
391
392 client_message = (struct netagent_client_message *)(void *)(message + sizeof(struct netagent_message_header));
393 uuid_copy(dst: client_message->client_id, src: client_id);
394
395 if ((error = netagent_send_ctl_data(control_unit: wrapper->control_unit, buffer: message, buffer_size: 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
403static int
404netagent_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(buffer: message, message_type, flags: 0, message_id: 0, error: 0, payload_length: 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(dst: client_message->client_id, src: client_id);
420 client_message->error_code = error_code;
421
422 if ((error = netagent_send_ctl_data(control_unit: wrapper->control_unit, buffer: message, buffer_size: 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
430static int
431netagent_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(buffer: message, message_type, flags: 0, message_id: 0, error: 0, payload_length: 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(dst: client_message->client_id, src: client_id);
447 memcpy(dst: client_message->group_members, src: group_members->group_members, n: group_members->group_members_length);
448
449 if ((error = netagent_send_ctl_data(control_unit: wrapper->control_unit, buffer: message, buffer_size: 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
457static int
458netagent_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(buffer: message, message_type, flags: 0, message_id: 0, error: 0, payload_length: 0);
471
472 if ((error = netagent_send_ctl_data(control_unit: wrapper->control_unit, buffer: message, buffer_size: 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
480static int
481netagent_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(buffer: response, message_type, NETAGENT_MESSAGE_FLAGS_RESPONSE, message_id, error: 0, payload_length: 0);
491
492 if ((error = netagent_send_ctl_data(control_unit: session->control_unit, buffer: response, buffer_size: response_size))) {
493 NETAGENTLOG0(LOG_ERR, "Failed to send response");
494 }
495
496 kfree_data(response, response_size);
497 return error;
498}
499
500static errno_t
501netagent_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(buffer: response, message_type, NETAGENT_MESSAGE_FLAGS_RESPONSE,
518 message_id, error: error_code, payload_length: 0);
519
520 if ((error = netagent_send_ctl_data(control_unit: session->control_unit, buffer: response, buffer_size: response_size))) {
521 NETAGENTLOG0(LOG_ERR, "Failed to send response");
522 }
523
524 kfree_data(response, response_size);
525 return error;
526}
527
528static errno_t
529netagent_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(mbuf: 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(mbuf: packet, offset: 0, length: sizeof(header), out_data: &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, message_id: header.message_id, payload_length: header.message_payload_length,
559 packet, offset: sizeof(header));
560 break;
561 }
562 case NETAGENT_MESSAGE_TYPE_UNREGISTER: {
563 netagent_handle_unregister_message(session, message_id: header.message_id, payload_length: header.message_payload_length,
564 packet, offset: sizeof(header));
565 break;
566 }
567 case NETAGENT_MESSAGE_TYPE_UPDATE: {
568 netagent_handle_update_message(session, message_id: header.message_id, payload_length: header.message_payload_length,
569 packet, offset: sizeof(header));
570 break;
571 }
572 case NETAGENT_MESSAGE_TYPE_GET: {
573 netagent_handle_get(session, message_id: header.message_id, payload_length: header.message_payload_length,
574 packet, offset: 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, message_id: header.message_id, payload_length: header.message_payload_length,
587 packet, offset: 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, message_type: header.message_type, message_id: header.message_id,
593 NETAGENT_MESSAGE_ERROR_UNKNOWN_TYPE);
594 break;
595 }
596 }
597
598done:
599 mbuf_freem(mbuf: packet);
600 return error;
601}
602
603static void
604netagent_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
610static errno_t
611netagent_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, buffer: data, buffer_length: 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, buffer: data, buffer_length: 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, buffer: data, buffer_length: len);
638 break;
639 }
640 default:
641 NETAGENTLOG0(LOG_ERR, "Received unknown option");
642 error = ENOPROTOOPT;
643 break;
644 }
645
646done:
647 return error;
648}
649
650static errno_t
651netagent_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, payload: data, payload_length: len);
668 break;
669 }
670 case NETAGENT_OPTION_TYPE_UPDATE: {
671 NETAGENTLOG0(LOG_DEBUG, "Request for update");
672 error = netagent_handle_update_setopt(session, payload: data, payload_length: len);
673 break;
674 }
675 case NETAGENT_OPTION_TYPE_UNREGISTER: {
676 NETAGENTLOG0(LOG_DEBUG, "Request for unregistration");
677 error = netagent_handle_unregister_setopt(session, payload: data, payload_length: 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, payload: data, payload_length: 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, payload: data, payload_length: 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, payload: data, payload_length: 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, payload: data, payload_length: 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, payload: data, payload_length: 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, buffer: data, buffer_length: 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, payload: data, payload_length: len);
713 break;
714 }
715 default:
716 NETAGENTLOG0(LOG_ERR, "Received unknown option");
717 error = ENOPROTOOPT;
718 break;
719 }
720
721done:
722 return error;
723}
724
725// Session Management
726static struct netagent_session *
727netagent_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(lck: &new_session->session_lock, grp: &netagent_mtx_grp, LCK_ATTR_NULL);
736
737 return new_session;
738}
739
740netagent_session_t
741netagent_create(netagent_event_f event_handler, void *context)
742{
743 struct netagent_session *session = netagent_create_session(control_unit: 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
753static void
754netagent_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
760static struct netagent_wrapper *
761netagent_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(lck: &new_wrapper->agent_lock, grp: &netagent_mtx_grp, LCK_ATTR_NULL);
771
772 return new_wrapper;
773}
774
775static void
776netagent_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(lck: &wrapper->agent_lock, grp: &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
797static void
798netagent_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(token: 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
820static void
821netagent_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(dst: unregistered_uuid, src: session->wrapper->netagent->netagent_uuid);
843
844 netagent_free_wrapper(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(agent_uuid: unregistered_uuid, KEV_NETAGENT_UNREGISTERED, TRUE, false);
855 }
856}
857
858static void
859netagent_delete_session(struct netagent_session *session)
860{
861 if (session != NULL) {
862 netagent_unregister_session_wrapper(session);
863 lck_mtx_destroy(lck: &session->session_lock, grp: &netagent_mtx_grp);
864 kfree_type(struct netagent_session, session);
865 }
866}
867
868void
869netagent_destroy(netagent_session_t session)
870{
871 return netagent_delete_session(session: (struct netagent_session *)session);
872}
873
874static size_t
875netagent_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(s: &netagent_peek, c: 0, n: sizeof(netagent_peek));
881
882 *err = 0;
883
884 error = mbuf_copydata(mbuf: packet, offset, length: sizeof(netagent_peek), out_data: &netagent_peek);
885 if (error) {
886 *err = ENOENT;
887 return 0;
888 }
889
890 return netagent_peek.netagent_data_size;
891}
892
893static errno_t
894netagent_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
926errno_t
927netagent_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(dst: new_wrapper->netagent, src: agent, n: sizeof(struct netagent) + data_size);
953
954 uuid_copy(dst: registered_uuid, src: 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(wrapper: new_wrapper);
959 return error;
960 }
961
962 NETAGENTLOG0(LOG_DEBUG, "Registered new agent");
963 netagent_post_event(agent_uuid: registered_uuid, KEV_NETAGENT_REGISTERED, TRUE, false);
964
965 return 0;
966}
967
968static errno_t
969netagent_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(dst: new_wrapper->netagent, src: register_netagent, n: sizeof(struct netagent) + data_size);
1012
1013 uuid_copy(dst: registered_uuid, src: 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(wrapper: new_wrapper);
1018 goto done;
1019 }
1020
1021 NETAGENTLOG0(LOG_DEBUG, "Registered new agent");
1022 netagent_post_event(agent_uuid: registered_uuid, KEV_NETAGENT_REGISTERED, TRUE, false);
1023
1024done:
1025 return response_error;
1026}
1027
1028static void
1029netagent_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, err: &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(mbuf: packet, offset, length: sizeof(struct netagent) + data_size,
1061 out_data: new_wrapper->netagent);
1062 if (error) {
1063 NETAGENTLOG(LOG_ERR, "Failed to read data into agent structure: %d", error);
1064 netagent_free_wrapper_memory(wrapper: new_wrapper);
1065 response_error = NETAGENT_MESSAGE_ERROR_INTERNAL;
1066 goto fail;
1067 }
1068
1069 uuid_copy(dst: registered_uuid, src: 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(wrapper: 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(agent_uuid: registered_uuid, KEV_NETAGENT_REGISTERED, TRUE, false);
1082 return;
1083fail:
1084 netagent_send_error_response(session, NETAGENT_MESSAGE_TYPE_REGISTER, message_id, error_code: response_error);
1085}
1086
1087errno_t
1088netagent_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
1100static errno_t
1101netagent_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
1115done:
1116 return response_error;
1117}
1118
1119static void
1120netagent_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;
1136fail:
1137 netagent_send_error_response(session, NETAGENT_MESSAGE_TYPE_UNREGISTER, message_id, error_code: response_error);
1138}
1139
1140static void
1141netagent_send_cellular_failed_event(struct netagent_wrapper *wrapper,
1142 pid_t pid, uuid_t proc_uuid)
1143{
1144 if (strncmp(s1: wrapper->netagent->netagent_domain, s2: "Cellular", NETAGENT_DOMAINSIZE) != 0) {
1145 return;
1146 }
1147
1148 struct kev_netpolicy_ifdenied ev_ifdenied;
1149
1150 bzero(s: &ev_ifdenied, n: sizeof(ev_ifdenied));
1151
1152 ev_ifdenied.ev_data.epid = (u_int64_t)pid;
1153 uuid_copy(dst: ev_ifdenied.ev_data.euuid, src: 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
1159static errno_t
1160netagent_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(uu1: session->wrapper->netagent->netagent_uuid, uu2: new_wrapper->netagent->netagent_uuid) != 0 ||
1183 memcmp(s1: &session->wrapper->netagent->netagent_domain, s2: &new_wrapper->netagent->netagent_domain,
1184 n: sizeof(new_wrapper->netagent->netagent_domain)) != 0 ||
1185 memcmp(s1: &session->wrapper->netagent->netagent_type, s2: &new_wrapper->netagent->netagent_type,
1186 n: 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(s1: session->wrapper->netagent, s2: new_wrapper->netagent, n: 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(client_id: search_client->client_id, remove_netagent_uuid: session->wrapper->netagent->netagent_uuid, agent_generation: session->wrapper->generation);
1222 netagent_send_cellular_failed_event(wrapper: new_wrapper, pid: search_client->client_pid, proc_uuid: 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(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
1269errno_t
1270netagent_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(dst: new_wrapper->netagent, src: agent, n: sizeof(struct netagent) + data_size);
1297
1298 uuid_copy(dst: updated_uuid, src: 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: &agent_changed, error_domain: kNetagentErrorDomainPOSIX);
1302 if (error == 0) {
1303 netagent_post_event(agent_uuid: updated_uuid, KEV_NETAGENT_UPDATED, update_necp: 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(wrapper: new_wrapper);
1307 }
1308 } else {
1309 netagent_free_wrapper_memory(wrapper: new_wrapper);
1310 return error;
1311 }
1312
1313 return 0;
1314}
1315
1316static errno_t
1317netagent_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(dst: new_wrapper->netagent, src: update_netagent, n: sizeof(struct netagent) + data_size);
1361
1362 uuid_copy(dst: updated_uuid, src: 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: &agent_changed, error_domain: kNetagentErrorDomainPOSIX);
1366 if (response_error == 0) {
1367 netagent_post_event(agent_uuid: updated_uuid, KEV_NETAGENT_UPDATED, update_necp: 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(wrapper: new_wrapper);
1371 }
1372 } else {
1373 netagent_free_wrapper_memory(wrapper: new_wrapper);
1374 }
1375
1376done:
1377 return response_error;
1378}
1379
1380static void
1381netagent_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, err: &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(mbuf: packet, offset, length: sizeof(struct netagent) + data_size, out_data: new_wrapper->netagent);
1415 if (error) {
1416 NETAGENTLOG(LOG_ERR, "Failed to read data into agent structure: %d", error);
1417 netagent_free_wrapper_memory(wrapper: new_wrapper);
1418 response_error = NETAGENT_MESSAGE_ERROR_INTERNAL;
1419 goto fail;
1420 }
1421
1422 uuid_copy(dst: updated_uuid, src: 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: &agent_changed, error_domain: 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(wrapper: new_wrapper);
1431 goto fail;
1432 }
1433
1434 netagent_send_success_response(session, NETAGENT_MESSAGE_TYPE_UPDATE, message_id);
1435
1436 netagent_post_event(agent_uuid: updated_uuid, KEV_NETAGENT_UPDATED, update_necp: 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(wrapper: new_wrapper);
1441 }
1442
1443 return;
1444fail:
1445 netagent_send_error_response(session, NETAGENT_MESSAGE_TYPE_UPDATE, message_id, error_code: response_error);
1446}
1447
1448static void
1449netagent_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(buffer: cursor, NETAGENT_MESSAGE_TYPE_GET,
1485 NETAGENT_MESSAGE_FLAGS_RESPONSE, message_id, error: 0,
1486 payload_length: response_size - sizeof(struct netagent_message_header));
1487 memcpy(dst: cursor, src: session->wrapper->netagent, n: 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(control_unit: session->control_unit, buffer: response, buffer_size: response_size)) {
1494 NETAGENTLOG0(LOG_ERR, "Failed to send response");
1495 }
1496 kfree_data(response, response_size);
1497 return;
1498fail:
1499 netagent_send_error_response(session, NETAGENT_MESSAGE_TYPE_GET, message_id, error_code: response_error);
1500}
1501
1502errno_t
1503netagent_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(dst: netagent_uuid, src: 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, client_id: necp_client_uuid, assigned_results: 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
1536errno_t
1537netagent_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(dst: netagent_uuid, src: 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_num: protoctl_event_tcp_seq_number);
1563
1564 return error;
1565}
1566
1567static errno_t
1568netagent_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(dst: netagent_uuid, src: 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(dst: client_id, src: assign_nexus_netagent->assign_client_id, n: 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(dst: assigned_results, src: assign_nexus_netagent->assign_necp_results, n: 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");
1631done:
1632 return response_error;
1633}
1634
1635
1636static void
1637netagent_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(dst: netagent_uuid, src: 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(mbuf: packet, offset, length: sizeof(client_id), out_data: &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(mbuf: packet, offset: offset + sizeof(client_id), length: assigned_results_length, out_data: 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;
1707fail:
1708 netagent_send_error_response(session, NETAGENT_MESSAGE_TYPE_ASSIGN_NEXUS, message_id, error_code: response_error);
1709}
1710
1711static errno_t
1712netagent_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(dst: netagent_uuid, src: 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(dst: client_id, src: assign_message->assign_client_id, n: 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(dst: assigned_group_members, src: assign_message->assign_necp_results, n: 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");
1777done:
1778 return response_error;
1779}
1780
1781
1782errno_t
1783netagent_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(dst: &use_count, src: payload, n: 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
1822done:
1823 return response_error;
1824}
1825
1826errno_t
1827netagent_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(dst: buffer, src: &use_count, n: sizeof(use_count));
1865 *buffer_length = sizeof(use_count);
1866
1867done:
1868 return response_error;
1869}
1870
1871static errno_t
1872netagent_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(dst: token_struct->token_bytes, src: token, n: 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);
1927done:
1928 return response_error;
1929}
1930
1931static errno_t
1932netagent_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(token: search_token);
1956 }
1957 session->wrapper->token_count = 0;
1958 NETAGENT_UNLOCK(session->wrapper);
1959 NETAGENT_SESSION_UNLOCK(session);
1960done:
1961 return response_error;
1962}
1963
1964static errno_t
1965netagent_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(dst: buffer, src: &token_count, n: sizeof(token_count));
2002 *buffer_length = sizeof(token_count);
2003
2004done:
2005 return response_error;
2006}
2007
2008static errno_t
2009netagent_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(dst: &token_low_water, src: buffer, n: 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
2047done:
2048 return response_error;
2049}
2050
2051static errno_t
2052netagent_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(dst: buffer, src: &token_low_water, n: sizeof(token_low_water));
2089 *buffer_length = sizeof(token_low_water);
2090
2091done:
2092 return response_error;
2093}
2094
2095static errno_t
2096netagent_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(token: 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);
2126done:
2127 return response_error;
2128}
2129
2130static struct netagent_wrapper *
2131netagent_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(uu1: search_netagent->netagent->netagent_uuid, uu2: 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
2153void
2154netagent_post_updated_interfaces(uuid_t uuid)
2155{
2156 if (!uuid_is_null(uu: uuid)) {
2157 netagent_post_event(agent_uuid: uuid, KEV_NETAGENT_UPDATED_INTERFACES, true, false);
2158 } else {
2159 NETAGENTLOG0(LOG_DEBUG, "Interface event with no associated agent");
2160 }
2161}
2162
2163static u_int32_t
2164netagent_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
2177static void
2178netagent_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(dst: cursor, src: search_netagent->netagent->netagent_uuid, n: sizeof(search_netagent->netagent->netagent_uuid));
2190 cursor += sizeof(search_netagent->netagent->netagent_uuid);
2191 }
2192}
2193
2194int
2195netagent_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(cred: kauth_cred_get(), PRIV_NET_PRIVILEGED_NECP_POLICIES, flags: 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(uuid: ifsir32->netagent_uuid, false, false);
2219 if (wrapper == NULL) {
2220 error = ENOENT;
2221 break;
2222 }
2223 uuid_copy(dst: ifsir32->netagent_uuid, src: wrapper->netagent->netagent_uuid);
2224 memcpy(dst: ifsir32->netagent_domain, src: wrapper->netagent->netagent_domain, n: sizeof(ifsir32->netagent_domain));
2225 memcpy(dst: ifsir32->netagent_type, src: wrapper->netagent->netagent_type, n: sizeof(ifsir32->netagent_type));
2226 memcpy(dst: ifsir32->netagent_desc, src: wrapper->netagent->netagent_desc, n: 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(uuid: ifsir64->netagent_uuid, false, false);
2244 if (wrapper == NULL) {
2245 error = ENOENT;
2246 break;
2247 }
2248 uuid_copy(dst: ifsir64->netagent_uuid, src: wrapper->netagent->netagent_uuid);
2249 memcpy(dst: ifsir64->netagent_domain, src: wrapper->netagent->netagent_domain, n: sizeof(ifsir64->netagent_domain));
2250 memcpy(dst: ifsir64->netagent_type, src: wrapper->netagent->netagent_type, n: sizeof(ifsir64->netagent_type));
2251 memcpy(dst: ifsir64->netagent_desc, src: wrapper->netagent->netagent_desc, n: 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(buffer: response, buffer_length: 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(buffer: response, buffer_length: 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
2323u_int32_t
2324netagent_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
2340errno_t
2341netagent_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(agent_uuid: uuid, KEV_NETAGENT_UPDATED, true, false);
2368 }
2369
2370 return error;
2371}
2372
2373u_int32_t
2374netagent_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
2390bool
2391netagent_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(dst: domain, src: wrapper->netagent->netagent_domain, NETAGENT_DOMAINSIZE);
2404 memcpy(dst: type, src: 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
2414int
2415netagent_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, p: current_proc(), NETAGENT_TRIGGER_FLAG_KERNEL, NETAGENT_MESSAGE_TYPE_TRIGGER);
2442 NETAGENTLOG((error ? LOG_ERR : LOG_INFO), "Triggered netagent from kernel (error %d)", error);
2443done:
2444 if (wrapper != NULL) {
2445 NETAGENT_UNLOCK(wrapper);
2446 }
2447 NETAGENT_LIST_UNLOCK();
2448 return error;
2449}
2450
2451int
2452netagent_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(uuid: 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(dst: report_proc_uuid, src: 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, pid: report_pid, proc_uuid: 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, client_id: necp_client_uuid, message_type, error_code: 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, client_id: necp_client_uuid, message_type, group_members: &parameters->u.group_members);
2596 } else {
2597 error = netagent_send_client_message(wrapper, client_id: 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(dst: new_pending_client->client_id, src: necp_client_uuid);
2608 if (parameters != NULL) {
2609 new_pending_client->client_pid = parameters->u.nexus_request.epid;
2610 uuid_copy(dst: new_pending_client->client_proc_uuid, src: 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(uu: agent_uuid, out: uuid_str);
2630 NETAGENTLOG(LOG_NOTICE, "Triggered network agent %s, error = %d", uuid_str, error);
2631 }
2632done:
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
2642int
2643netagent_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
2648int
2649netagent_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(uuid: 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
2668done:
2669 if (wrapper != NULL) {
2670 NETAGENT_UNLOCK(wrapper);
2671 }
2672 NETAGENT_LIST_UNLOCK();
2673 return error;
2674}
2675
2676int
2677netagent_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(uuid: 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);
2699done:
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
2709int
2710netagent_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(uuid: 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, result: &deadline);
2733 clock_absolutetime_interval_to_deadline(abstime: deadline, result: &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 }
2763done:
2764 if (wrapper != NULL) {
2765 NETAGENT_UNLOCK(wrapper);
2766 }
2767 NETAGENT_LIST_UNLOCK();
2768 return error;
2769}
2770
2771int
2772netagent_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(uu: 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(uuid: 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);
2826done:
2827 if (wrapper != NULL) {
2828 NETAGENT_UNLOCK(wrapper);
2829 }
2830 NETAGENT_LIST_UNLOCK();
2831 return error;
2832}
2833