]> git.saurik.com Git - apple/xnu.git/blame - bsd/net/network_agent.c
xnu-6153.101.6.tar.gz
[apple/xnu.git] / bsd / net / network_agent.c
CommitLineData
3e170ce0 1/*
a39ff7e2 2 * Copyright (c) 2014-2018 Apple Inc. All rights reserved.
3e170ce0
A
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29#include <string.h>
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 <libkern/OSMalloc.h>
36#include <sys/kernel.h>
37#include <sys/kern_control.h>
38#include <sys/mbuf.h>
39#include <sys/kpi_mbuf.h>
40#include <sys/sysctl.h>
41#include <sys/priv.h>
42#include <sys/kern_event.h>
43#include <sys/sysproto.h>
44#include <net/network_agent.h>
45#include <net/if_var.h>
39037602 46#include <net/necp.h>
cb323159 47#include <os/log.h>
3e170ce0
A
48
49u_int32_t netagent_debug = LOG_NOTICE; // 0=None, 1=Basic
50
51SYSCTL_NODE(_net, OID_AUTO, netagent, CTLFLAG_RW | CTLFLAG_LOCKED, 0, "NetworkAgent");
52SYSCTL_INT(_net_netagent, OID_AUTO, debug, CTLFLAG_LOCKED | CTLFLAG_RW, &netagent_debug, 0, "");
53
54static int netagent_registered_count = 0;
0a7de745
A
55SYSCTL_INT(_net_netagent, OID_AUTO, registered_count, CTLFLAG_RD | CTLFLAG_LOCKED,
56 &netagent_registered_count, 0, "");
3e170ce0
A
57
58static int netagent_active_count = 0;
0a7de745
A
59SYSCTL_INT(_net_netagent, OID_AUTO, active_count, CTLFLAG_RD | CTLFLAG_LOCKED,
60 &netagent_active_count, 0, "");
3e170ce0 61
cb323159
A
62#define NETAGENTLOG(level, format, ...) do { \
63 if (level <= netagent_debug) { \
64 if (level == LOG_ERR) { \
65 os_log_error(OS_LOG_DEFAULT, "%s: " format "\n", __FUNCTION__, __VA_ARGS__); \
66 } else { \
67 os_log(OS_LOG_DEFAULT, "%s: " format "\n", __FUNCTION__, __VA_ARGS__); \
68 } \
69 } \
3e170ce0
A
70} while (0)
71
cb323159
A
72#define NETAGENTLOG0(level, msg) do { \
73 if (level <= netagent_debug) { \
74 if (level == LOG_ERR) { \
75 os_log_error(OS_LOG_DEFAULT, "%s: %s\n", __FUNCTION__, msg); \
76 } else { \
77 os_log(OS_LOG_DEFAULT, "%s: %s\n", __FUNCTION__, msg); \
78 } \
79 } \
3e170ce0
A
80} while (0)
81
39037602
A
82struct netagent_client {
83 LIST_ENTRY(netagent_client) client_chain;
84 uuid_t client_id;
85 uuid_t client_proc_uuid;
86 pid_t client_pid;
3e170ce0
A
87};
88
39037602
A
89LIST_HEAD(netagent_client_list_s, netagent_client);
90
3e170ce0
A
91struct netagent_wrapper {
92 LIST_ENTRY(netagent_wrapper) master_chain;
93 u_int32_t control_unit;
5ba3f43e
A
94 netagent_event_f event_handler;
95 void *event_context;
39037602 96 u_int32_t generation;
813fb2f6 97 u_int64_t use_count;
39037602 98 struct netagent_client_list_s pending_triggers_list;
3e170ce0
A
99 struct netagent netagent;
100};
101
102struct netagent_session {
5ba3f43e 103 u_int32_t control_unit; // A control unit of 0 indicates an agent owned by the kernel
3e170ce0 104 struct netagent_wrapper *wrapper;
5ba3f43e
A
105 netagent_event_f event_handler;
106 void *event_context;
3e170ce0
A
107};
108
39037602 109typedef enum {
0a7de745
A
110 kNetagentErrorDomainPOSIX = 0,
111 kNetagentErrorDomainUserDefined = 1,
39037602
A
112} netagent_error_domain_t;
113
3e170ce0
A
114static LIST_HEAD(_netagent_list, netagent_wrapper) master_netagent_list;
115
39037602
A
116// Protected by netagent_lock
117static u_int32_t g_next_generation = 1;
118
0a7de745
A
119static kern_ctl_ref netagent_kctlref;
120static u_int32_t netagent_family;
121static OSMallocTag netagent_malloc_tag;
122static lck_grp_attr_t *netagent_grp_attr = NULL;
123static lck_attr_t *netagent_mtx_attr = NULL;
124static lck_grp_t *netagent_mtx_grp = NULL;
3e170ce0
A
125decl_lck_rw_data(static, netagent_lock);
126
127static errno_t netagent_register_control(void);
128static errno_t netagent_ctl_connect(kern_ctl_ref kctlref, struct sockaddr_ctl *sac,
0a7de745 129 void **unitinfo);
3e170ce0
A
130static errno_t netagent_ctl_disconnect(kern_ctl_ref kctlref, u_int32_t unit, void *unitinfo);
131static errno_t netagent_ctl_send(kern_ctl_ref kctlref, u_int32_t unit, void *unitinfo,
0a7de745 132 mbuf_t m, int flags);
3e170ce0
A
133static void netagent_ctl_rcvd(kern_ctl_ref kctlref, u_int32_t unit, void *unitinfo, int flags);
134static errno_t netagent_ctl_getopt(kern_ctl_ref kctlref, u_int32_t unit, void *unitinfo,
0a7de745 135 int opt, void *data, size_t *len);
3e170ce0 136static errno_t netagent_ctl_setopt(kern_ctl_ref kctlref, u_int32_t unit, void *unitinfo,
0a7de745 137 int opt, void *data, size_t len);
3e170ce0
A
138
139static int netagent_send_ctl_data(u_int32_t control_unit, u_int8_t *buffer, size_t buffer_size);
140
141static struct netagent_session *netagent_create_session(u_int32_t control_unit);
142static void netagent_delete_session(struct netagent_session *session);
143
39037602
A
144// Register
145static void netagent_handle_register_message(struct netagent_session *session, u_int32_t message_id,
0a7de745 146 u_int32_t payload_length, mbuf_t packet, int offset);
39037602 147static errno_t netagent_handle_register_setopt(struct netagent_session *session, u_int8_t *payload,
0a7de745 148 u_int32_t payload_length);
39037602
A
149
150// Unregister
151static void netagent_handle_unregister_message(struct netagent_session *session, u_int32_t message_id,
0a7de745 152 u_int32_t payload_length, mbuf_t packet, int offset);
39037602 153static errno_t netagent_handle_unregister_setopt(struct netagent_session *session, u_int8_t *payload,
0a7de745 154 u_int32_t payload_length);
39037602
A
155
156// Update
157static void netagent_handle_update_message(struct netagent_session *session, u_int32_t message_id,
0a7de745 158 u_int32_t payload_length, mbuf_t packet, int offset);
39037602 159static errno_t netagent_handle_update_setopt(struct netagent_session *session, u_int8_t *payload,
0a7de745 160 u_int32_t payload_length);
39037602
A
161
162// Assign nexus
163static void netagent_handle_assign_nexus_message(struct netagent_session *session, u_int32_t message_id,
0a7de745 164 u_int32_t payload_length, mbuf_t packet, int offset);
39037602 165static errno_t netagent_handle_assign_nexus_setopt(struct netagent_session *session, u_int8_t *payload,
0a7de745 166 u_int32_t payload_length);
39037602 167
813fb2f6
A
168// Set/get assert count
169static errno_t netagent_handle_use_count_setopt(struct netagent_session *session, u_int8_t *payload, size_t payload_length);
170static errno_t netagent_handle_use_count_getopt(struct netagent_session *session, u_int8_t *buffer, size_t *buffer_length);
171
3e170ce0 172static void netagent_handle_get(struct netagent_session *session, u_int32_t message_id,
0a7de745 173 u_int32_t payload_length, mbuf_t packet, int offset);
3e170ce0
A
174
175static struct netagent_wrapper *netagent_find_agent_with_uuid(uuid_t uuid);
176
177errno_t
178netagent_init(void)
179{
180 errno_t result = 0;
181
182 result = netagent_register_control();
183 if (result != 0) {
184 goto done;
185 }
186
187 netagent_grp_attr = lck_grp_attr_alloc_init();
188 if (netagent_grp_attr == NULL) {
189 NETAGENTLOG0(LOG_ERR, "lck_grp_attr_alloc_init failed");
190 result = ENOMEM;
191 goto done;
192 }
193
194 netagent_mtx_grp = lck_grp_alloc_init(NETAGENT_CONTROL_NAME, netagent_grp_attr);
195 if (netagent_mtx_grp == NULL) {
196 NETAGENTLOG0(LOG_ERR, "lck_grp_alloc_init failed");
197 result = ENOMEM;
198 goto done;
199 }
200
201 netagent_mtx_attr = lck_attr_alloc_init();
202 if (netagent_mtx_attr == NULL) {
203 NETAGENTLOG0(LOG_ERR, "lck_attr_alloc_init failed");
204 result = ENOMEM;
205 goto done;
206 }
207
208 lck_rw_init(&netagent_lock, netagent_mtx_grp, netagent_mtx_attr);
209
210 LIST_INIT(&master_netagent_list);
211
212done:
213 if (result != 0) {
214 if (netagent_mtx_attr != NULL) {
215 lck_attr_free(netagent_mtx_attr);
216 netagent_mtx_attr = NULL;
217 }
218 if (netagent_mtx_grp != NULL) {
219 lck_grp_free(netagent_mtx_grp);
220 netagent_mtx_grp = NULL;
221 }
222 if (netagent_grp_attr != NULL) {
223 lck_grp_attr_free(netagent_grp_attr);
224 netagent_grp_attr = NULL;
225 }
226 if (netagent_kctlref != NULL) {
227 ctl_deregister(netagent_kctlref);
228 netagent_kctlref = NULL;
229 }
230 }
0a7de745 231 return result;
3e170ce0
A
232}
233
234static errno_t
235netagent_register_control(void)
236{
0a7de745
A
237 struct kern_ctl_reg kern_ctl;
238 errno_t result = 0;
3e170ce0
A
239
240 // Create a tag to allocate memory
241 netagent_malloc_tag = OSMalloc_Tagalloc(NETAGENT_CONTROL_NAME, OSMT_DEFAULT);
242
243 // Find a unique value for our interface family
244 result = mbuf_tag_id_find(NETAGENT_CONTROL_NAME, &netagent_family);
245 if (result != 0) {
246 NETAGENTLOG(LOG_ERR, "mbuf_tag_id_find_internal failed: %d", result);
0a7de745 247 return result;
3e170ce0
A
248 }
249
250 bzero(&kern_ctl, sizeof(kern_ctl));
251 strlcpy(kern_ctl.ctl_name, NETAGENT_CONTROL_NAME, sizeof(kern_ctl.ctl_name));
252 kern_ctl.ctl_name[sizeof(kern_ctl.ctl_name) - 1] = 0;
253 kern_ctl.ctl_flags = CTL_FLAG_PRIVILEGED; // Require root
254 kern_ctl.ctl_sendsize = 64 * 1024;
255 kern_ctl.ctl_recvsize = 64 * 1024;
256 kern_ctl.ctl_connect = netagent_ctl_connect;
257 kern_ctl.ctl_disconnect = netagent_ctl_disconnect;
258 kern_ctl.ctl_send = netagent_ctl_send;
259 kern_ctl.ctl_rcvd = netagent_ctl_rcvd;
260 kern_ctl.ctl_setopt = netagent_ctl_setopt;
261 kern_ctl.ctl_getopt = netagent_ctl_getopt;
262
263 result = ctl_register(&kern_ctl, &netagent_kctlref);
264 if (result != 0) {
265 NETAGENTLOG(LOG_ERR, "ctl_register failed: %d", result);
0a7de745 266 return result;
3e170ce0
A
267 }
268
0a7de745 269 return 0;
3e170ce0
A
270}
271
272static errno_t
273netagent_ctl_connect(kern_ctl_ref kctlref, struct sockaddr_ctl *sac, void **unitinfo)
274{
275#pragma unused(kctlref)
276 *unitinfo = netagent_create_session(sac->sc_unit);
277 if (*unitinfo == NULL) {
278 // Could not allocate session
0a7de745 279 return ENOBUFS;
3e170ce0
A
280 }
281
0a7de745 282 return 0;
3e170ce0
A
283}
284
285static errno_t
286netagent_ctl_disconnect(kern_ctl_ref kctlref, u_int32_t unit, void *unitinfo)
287{
288#pragma unused(kctlref, unit)
289 struct netagent_session *session = (struct netagent_session *)unitinfo;
290 if (session != NULL) {
291 netagent_delete_session(session);
292 }
293
0a7de745 294 return 0;
3e170ce0
A
295}
296
297// Kernel events
298static void
cb323159 299netagent_post_event(uuid_t agent_uuid, u_int32_t event_code, bool update_necp, bool should_update_immediately)
3e170ce0 300{
39037602 301 if (update_necp) {
cb323159 302 necp_update_all_clients_immediately_if_needed(should_update_immediately);
39037602
A
303 }
304
3e170ce0
A
305 struct kev_msg ev_msg;
306 memset(&ev_msg, 0, sizeof(ev_msg));
307
308 struct kev_netagent_data event_data;
309
0a7de745
A
310 ev_msg.vendor_code = KEV_VENDOR_APPLE;
311 ev_msg.kev_class = KEV_NETWORK_CLASS;
312 ev_msg.kev_subclass = KEV_NETAGENT_SUBCLASS;
313 ev_msg.event_code = event_code;
3e170ce0
A
314
315 uuid_copy(event_data.netagent_uuid, agent_uuid);
0a7de745 316 ev_msg.dv[0].data_ptr = &event_data;
3e170ce0
A
317 ev_msg.dv[0].data_length = sizeof(event_data);
318
319 kev_post_msg(&ev_msg);
320}
321
322// Message handling
323static u_int8_t *
324netagent_buffer_write_message_header(u_int8_t *buffer, u_int8_t message_type, u_int8_t flags,
0a7de745 325 u_int32_t message_id, u_int32_t error, u_int32_t payload_length)
3e170ce0
A
326{
327 ((struct netagent_message_header *)(void *)buffer)->message_type = message_type;
328 ((struct netagent_message_header *)(void *)buffer)->message_flags = flags;
329 ((struct netagent_message_header *)(void *)buffer)->message_id = message_id;
330 ((struct netagent_message_header *)(void *)buffer)->message_error = error;
331 ((struct netagent_message_header *)(void *)buffer)->message_payload_length = payload_length;
0a7de745 332 return buffer + sizeof(struct netagent_message_header);
3e170ce0
A
333}
334
335static int
336netagent_send_ctl_data(u_int32_t control_unit, u_int8_t *buffer, size_t buffer_size)
337{
338 if (netagent_kctlref == NULL || control_unit == 0 || buffer == NULL || buffer_size == 0) {
0a7de745 339 return EINVAL;
3e170ce0
A
340 }
341
342 return ctl_enqueuedata(netagent_kctlref, control_unit, buffer, buffer_size, CTL_DATA_EOR);
343}
344
345static int
346netagent_send_trigger(struct netagent_wrapper *wrapper, struct proc *p, u_int32_t flags, u_int32_t trigger_type)
347{
348 int error = 0;
349 struct netagent_trigger_message *trigger_message = NULL;
350 u_int8_t *trigger = NULL;
351 size_t trigger_size = sizeof(struct netagent_message_header) + sizeof(struct netagent_trigger_message);
352
353 MALLOC(trigger, u_int8_t *, trigger_size, M_NETAGENT, M_WAITOK);
354 if (trigger == NULL) {
0a7de745 355 return ENOMEM;
3e170ce0
A
356 }
357
358 (void)netagent_buffer_write_message_header(trigger, trigger_type, 0, 0, 0, sizeof(struct netagent_trigger_message));
359
360 trigger_message = (struct netagent_trigger_message *)(void *)(trigger + sizeof(struct netagent_message_header));
361 trigger_message->trigger_flags = flags;
362 if (p != NULL) {
363 trigger_message->trigger_pid = proc_pid(p);
364 proc_getexecutableuuid(p, trigger_message->trigger_proc_uuid, sizeof(trigger_message->trigger_proc_uuid));
365 } else {
366 trigger_message->trigger_pid = 0;
367 uuid_clear(trigger_message->trigger_proc_uuid);
368 }
369
370 if ((error = netagent_send_ctl_data(wrapper->control_unit, (u_int8_t *)trigger, trigger_size))) {
371 NETAGENTLOG(LOG_ERR, "Failed to send trigger message on control unit %d", wrapper->control_unit);
372 }
373
374 FREE(trigger, M_NETAGENT);
0a7de745 375 return error;
3e170ce0
A
376}
377
39037602
A
378static int
379netagent_send_client_message(struct netagent_wrapper *wrapper, uuid_t client_id, u_int8_t message_type)
380{
381 int error = 0;
382 struct netagent_client_message *client_message = NULL;
383 u_int8_t *message = NULL;
384 size_t message_size = sizeof(struct netagent_message_header) + sizeof(struct netagent_client_message);
385
386 MALLOC(message, u_int8_t *, message_size, M_NETAGENT, M_WAITOK);
387 if (message == NULL) {
0a7de745 388 return ENOMEM;
39037602
A
389 }
390
391 (void)netagent_buffer_write_message_header(message, message_type, 0, 0, 0, sizeof(struct netagent_client_message));
392
393 client_message = (struct netagent_client_message *)(void *)(message + sizeof(struct netagent_message_header));
394 uuid_copy(client_message->client_id, client_id);
395
396 if ((error = netagent_send_ctl_data(wrapper->control_unit, (u_int8_t *)message, message_size))) {
397 NETAGENTLOG(LOG_ERR, "Failed to send client message %d on control unit %d", message_type, wrapper->control_unit);
398 }
399
400 FREE(message, M_NETAGENT);
0a7de745 401 return error;
39037602
A
402}
403
3e170ce0
A
404static int
405netagent_send_success_response(struct netagent_session *session, u_int8_t message_type, u_int32_t message_id)
406{
407 int error = 0;
408 u_int8_t *response = NULL;
409 size_t response_size = sizeof(struct netagent_message_header);
410 MALLOC(response, u_int8_t *, response_size, M_NETAGENT, M_WAITOK);
411 if (response == NULL) {
0a7de745 412 return ENOMEM;
3e170ce0
A
413 }
414 (void)netagent_buffer_write_message_header(response, message_type, NETAGENT_MESSAGE_FLAGS_RESPONSE, message_id, 0, 0);
415
416 if ((error = netagent_send_ctl_data(session->control_unit, (u_int8_t *)response, response_size))) {
417 NETAGENTLOG0(LOG_ERR, "Failed to send response");
418 }
419
420 FREE(response, M_NETAGENT);
0a7de745 421 return error;
3e170ce0
A
422}
423
424static int
425netagent_send_error_response(struct netagent_session *session, u_int8_t message_type,
0a7de745 426 u_int32_t message_id, u_int32_t error_code)
3e170ce0
A
427{
428 int error = 0;
429 u_int8_t *response = NULL;
430 size_t response_size = sizeof(struct netagent_message_header);
d9a64523
A
431
432 if (session == NULL) {
433 NETAGENTLOG0(LOG_ERR, "Got a NULL session");
0a7de745 434 return EINVAL;
d9a64523
A
435 }
436
3e170ce0
A
437 MALLOC(response, u_int8_t *, response_size, M_NETAGENT, M_WAITOK);
438 if (response == NULL) {
0a7de745 439 return ENOMEM;
3e170ce0
A
440 }
441 (void)netagent_buffer_write_message_header(response, message_type, NETAGENT_MESSAGE_FLAGS_RESPONSE,
0a7de745 442 message_id, error_code, 0);
3e170ce0
A
443
444 if ((error = netagent_send_ctl_data(session->control_unit, (u_int8_t *)response, response_size))) {
445 NETAGENTLOG0(LOG_ERR, "Failed to send response");
446 }
447
448 FREE(response, M_NETAGENT);
0a7de745 449 return error;
3e170ce0
A
450}
451
452static errno_t
453netagent_ctl_send(kern_ctl_ref kctlref, u_int32_t unit, void *unitinfo, mbuf_t packet, int flags)
454{
455#pragma unused(kctlref, unit, flags)
456 struct netagent_session *session = (struct netagent_session *)unitinfo;
457 struct netagent_message_header header;
458 int error = 0;
459
460 if (session == NULL) {
461 NETAGENTLOG0(LOG_ERR, "Got a NULL session");
462 error = EINVAL;
463 goto done;
464 }
465
466 if (mbuf_pkthdr_len(packet) < sizeof(header)) {
467 NETAGENTLOG(LOG_ERR, "Got a bad packet, length (%lu) < sizeof header (%lu)",
0a7de745 468 mbuf_pkthdr_len(packet), sizeof(header));
3e170ce0
A
469 error = EINVAL;
470 goto done;
471 }
472
473 error = mbuf_copydata(packet, 0, sizeof(header), &header);
474 if (error) {
475 NETAGENTLOG(LOG_ERR, "mbuf_copydata failed for the header: %d", error);
476 error = ENOBUFS;
477 goto done;
478 }
479
480 switch (header.message_type) {
0a7de745
A
481 case NETAGENT_MESSAGE_TYPE_REGISTER: {
482 netagent_handle_register_message(session, header.message_id, header.message_payload_length,
483 packet, sizeof(header));
484 break;
485 }
486 case NETAGENT_MESSAGE_TYPE_UNREGISTER: {
487 netagent_handle_unregister_message(session, header.message_id, header.message_payload_length,
488 packet, sizeof(header));
489 break;
490 }
491 case NETAGENT_MESSAGE_TYPE_UPDATE: {
492 netagent_handle_update_message(session, header.message_id, header.message_payload_length,
493 packet, sizeof(header));
494 break;
495 }
496 case NETAGENT_MESSAGE_TYPE_GET: {
497 netagent_handle_get(session, header.message_id, header.message_payload_length,
498 packet, sizeof(header));
499 break;
500 }
501 case NETAGENT_MESSAGE_TYPE_ASSERT: {
502 NETAGENTLOG0(LOG_ERR, "NETAGENT_MESSAGE_TYPE_ASSERT no longer supported");
503 break;
504 }
505 case NETAGENT_MESSAGE_TYPE_UNASSERT: {
506 NETAGENTLOG0(LOG_ERR, "NETAGENT_MESSAGE_TYPE_UNASSERT no longer supported");
507 break;
508 }
509 case NETAGENT_MESSAGE_TYPE_ASSIGN_NEXUS: {
510 netagent_handle_assign_nexus_message(session, header.message_id, header.message_payload_length,
511 packet, sizeof(header));
512 break;
513 }
514 default: {
515 NETAGENTLOG(LOG_ERR, "Received unknown message type %d", header.message_type);
516 netagent_send_error_response(session, header.message_type, header.message_id,
517 NETAGENT_MESSAGE_ERROR_UNKNOWN_TYPE);
518 break;
519 }
3e170ce0
A
520 }
521
522done:
523 mbuf_freem(packet);
0a7de745 524 return error;
3e170ce0
A
525}
526
527static void
528netagent_ctl_rcvd(kern_ctl_ref kctlref, u_int32_t unit, void *unitinfo, int flags)
529{
530#pragma unused(kctlref, unit, unitinfo, flags)
531 return;
532}
533
534static errno_t
535netagent_ctl_getopt(kern_ctl_ref kctlref, u_int32_t unit, void *unitinfo, int opt,
0a7de745 536 void *data, size_t *len)
3e170ce0 537{
813fb2f6
A
538#pragma unused(kctlref, unit)
539 struct netagent_session *session = (struct netagent_session *)unitinfo;
540 errno_t error;
541
542 if (session == NULL) {
543 NETAGENTLOG0(LOG_ERR, "Received a NULL session");
544 error = EINVAL;
545 goto done;
546 }
547
548 switch (opt) {
0a7de745
A
549 case NETAGENT_OPTION_TYPE_USE_COUNT: {
550 NETAGENTLOG0(LOG_DEBUG, "Request to get use count");
551 error = netagent_handle_use_count_getopt(session, data, len);
552 }
553 break;
554 default:
555 NETAGENTLOG0(LOG_ERR, "Received unknown option");
556 error = ENOPROTOOPT;
813fb2f6
A
557 break;
558 }
559
560done:
0a7de745 561 return error;
3e170ce0
A
562}
563
564static errno_t
565netagent_ctl_setopt(kern_ctl_ref kctlref, u_int32_t unit, void *unitinfo, int opt,
0a7de745 566 void *data, size_t len)
3e170ce0 567{
39037602
A
568#pragma unused(kctlref, unit)
569 struct netagent_session *session = (struct netagent_session *)unitinfo;
570 errno_t error;
571
572 if (session == NULL) {
573 NETAGENTLOG0(LOG_ERR, "Received a NULL session");
574 error = EINVAL;
575 goto done;
576 }
577
578 switch (opt) {
0a7de745
A
579 case NETAGENT_OPTION_TYPE_REGISTER: {
580 NETAGENTLOG0(LOG_DEBUG, "Request for registration");
581 error = netagent_handle_register_setopt(session, data, len);
582 }
583 break;
584 case NETAGENT_OPTION_TYPE_UPDATE: {
585 NETAGENTLOG0(LOG_DEBUG, "Request for update");
586 error = netagent_handle_update_setopt(session, data, len);
587 }
588 break;
589 case NETAGENT_OPTION_TYPE_UNREGISTER: {
590 NETAGENTLOG0(LOG_DEBUG, "Request for unregistration");
591 error = netagent_handle_unregister_setopt(session, data, len);
592 }
593 break;
594 case NETAGENT_OPTION_TYPE_ASSIGN_NEXUS: {
595 NETAGENTLOG0(LOG_DEBUG, "Request for assigning nexus");
596 error = netagent_handle_assign_nexus_setopt(session, data, len);
597 }
598 break;
599 case NETAGENT_OPTION_TYPE_USE_COUNT: {
600 NETAGENTLOG0(LOG_DEBUG, "Request to set use count");
601 error = netagent_handle_use_count_setopt(session, data, len);
602 }
603 break;
604 default:
605 NETAGENTLOG0(LOG_ERR, "Received unknown option");
606 error = ENOPROTOOPT;
39037602
A
607 break;
608 }
609
610done:
0a7de745 611 return error;
3e170ce0
A
612}
613
614// Session Management
615static struct netagent_session *
616netagent_create_session(u_int32_t control_unit)
617{
618 struct netagent_session *new_session = NULL;
619
620 MALLOC(new_session, struct netagent_session *, sizeof(*new_session), M_NETAGENT, M_WAITOK);
621 if (new_session == NULL) {
622 goto done;
623 }
624 NETAGENTLOG(LOG_DEBUG, "Create agent session, control unit %d", control_unit);
625 memset(new_session, 0, sizeof(*new_session));
626 new_session->control_unit = control_unit;
3e170ce0
A
627 new_session->wrapper = NULL;
628done:
0a7de745 629 return new_session;
3e170ce0
A
630}
631
0a7de745
A
632netagent_session_t
633netagent_create(netagent_event_f event_handler, void *context)
5ba3f43e
A
634{
635 struct netagent_session *session = netagent_create_session(0);
636 if (session == NULL) {
637 return NULL;
638 }
639
640 session->event_handler = event_handler;
641 session->event_context = context;
642 return session;
643}
644
39037602
A
645static void
646netagent_free_wrapper(struct netagent_wrapper *wrapper)
647{
648 // Free any pending client triggers
649 struct netagent_client *search_client = NULL;
650 struct netagent_client *temp_client = NULL;
651 LIST_FOREACH_SAFE(search_client, &wrapper->pending_triggers_list, client_chain, temp_client) {
652 LIST_REMOVE(search_client, client_chain);
653 FREE(search_client, M_NETAGENT);
654 }
655
656 // Free wrapper itself
657 FREE(wrapper, M_NETAGENT);
658}
659
3e170ce0
A
660static void
661netagent_unregister_session_wrapper(struct netagent_session *session)
662{
663 bool unregistered = FALSE;
664 uuid_t unregistered_uuid;
665 struct netagent_wrapper *wrapper = NULL;
666 lck_rw_lock_exclusive(&netagent_lock);
667 if (session != NULL) {
668 wrapper = session->wrapper;
669 if (wrapper != NULL) {
670 if (netagent_registered_count > 0) {
671 netagent_registered_count--;
672 }
673 if ((session->wrapper->netagent.netagent_flags & NETAGENT_FLAG_ACTIVE) &&
0a7de745 674 netagent_active_count > 0) {
3e170ce0
A
675 netagent_active_count--;
676 }
677
678 LIST_REMOVE(wrapper, master_chain);
679
680 unregistered = TRUE;
681 uuid_copy(unregistered_uuid, session->wrapper->netagent.netagent_uuid);
682
39037602 683 netagent_free_wrapper(session->wrapper);
3e170ce0
A
684 session->wrapper = NULL;
685 NETAGENTLOG0(LOG_DEBUG, "Unregistered agent");
686 }
687 }
688 lck_rw_done(&netagent_lock);
689
690 if (unregistered) {
3e170ce0 691 ifnet_clear_netagent(unregistered_uuid);
cb323159 692 netagent_post_event(unregistered_uuid, KEV_NETAGENT_UNREGISTERED, TRUE, false);
3e170ce0
A
693 }
694}
695
696static void
697netagent_delete_session(struct netagent_session *session)
698{
699 if (session != NULL) {
700 netagent_unregister_session_wrapper(session);
3e170ce0
A
701 FREE(session, M_NETAGENT);
702 }
703}
704
0a7de745
A
705void
706netagent_destroy(netagent_session_t session)
5ba3f43e
A
707{
708 return netagent_delete_session((struct netagent_session *)session);
709}
710
3e170ce0
A
711static int
712netagent_packet_get_netagent_data_size(mbuf_t packet, int offset, int *err)
713{
714 int error = 0;
715
716 struct netagent netagent_peek;
717 memset(&netagent_peek, 0, sizeof(netagent_peek));
718
719 *err = 0;
720
721 error = mbuf_copydata(packet, offset, sizeof(netagent_peek), &netagent_peek);
722 if (error) {
723 *err = ENOENT;
0a7de745 724 return -1;
3e170ce0
A
725 }
726
0a7de745 727 return netagent_peek.netagent_data_size;
3e170ce0
A
728}
729
39037602
A
730static errno_t
731netagent_handle_register_inner(struct netagent_session *session, struct netagent_wrapper *new_wrapper)
732{
733 lck_rw_lock_exclusive(&netagent_lock);
734
ea3f0419
A
735 if (session->wrapper != NULL) {
736 lck_rw_done(&netagent_lock);
737 return EINVAL;
738 }
739
39037602 740 new_wrapper->control_unit = session->control_unit;
5ba3f43e
A
741 new_wrapper->event_handler = session->event_handler;
742 new_wrapper->event_context = session->event_context;
39037602
A
743 new_wrapper->generation = g_next_generation++;
744
745 session->wrapper = new_wrapper;
746 LIST_INSERT_HEAD(&master_netagent_list, new_wrapper, master_chain);
747 LIST_INIT(&new_wrapper->pending_triggers_list);
748
749 new_wrapper->netagent.netagent_flags |= NETAGENT_FLAG_REGISTERED;
750 netagent_registered_count++;
751 if (new_wrapper->netagent.netagent_flags & NETAGENT_FLAG_ACTIVE) {
752 netagent_active_count++;
753 }
754
755 lck_rw_done(&netagent_lock);
756
757 return 0;
758}
759
5ba3f43e
A
760errno_t
761netagent_register(netagent_session_t _session, struct netagent *agent)
762{
763 int data_size = 0;
764 struct netagent_wrapper *new_wrapper = NULL;
ea3f0419 765 uuid_t registered_uuid;
5ba3f43e
A
766
767 struct netagent_session *session = (struct netagent_session *)_session;
768 if (session == NULL) {
769 NETAGENTLOG0(LOG_ERR, "Cannot register agent on NULL session");
770 return EINVAL;
771 }
772
773 if (agent == NULL) {
774 NETAGENTLOG0(LOG_ERR, "Cannot register NULL agent");
775 return EINVAL;
776 }
777
778 if (session->wrapper != NULL) {
779 NETAGENTLOG0(LOG_ERR, "Session already has a registered agent");
780 return EINVAL;
781 }
782
783 data_size = agent->netagent_data_size;
784 if (data_size < 0 || data_size > NETAGENT_MAX_DATA_SIZE) {
785 NETAGENTLOG(LOG_ERR, "Register message size could not be read, data_size %d",
0a7de745 786 data_size);
5ba3f43e
A
787 return EINVAL;
788 }
789
790 MALLOC(new_wrapper, struct netagent_wrapper *, sizeof(*new_wrapper) + data_size, M_NETAGENT, M_WAITOK);
791 if (new_wrapper == NULL) {
792 NETAGENTLOG0(LOG_ERR, "Failed to allocate agent");
793 return ENOMEM;
794 }
795
796 memset(new_wrapper, 0, sizeof(*new_wrapper) + data_size);
cb323159 797 __nochk_memcpy(&new_wrapper->netagent, agent, sizeof(struct netagent) + data_size);
5ba3f43e 798
ea3f0419
A
799 uuid_copy(registered_uuid, new_wrapper->netagent.netagent_uuid);
800
5ba3f43e
A
801 int error = netagent_handle_register_inner(session, new_wrapper);
802 if (error != 0) {
803 FREE(new_wrapper, M_NETAGENT);
804 return error;
805 }
806
807 NETAGENTLOG0(LOG_DEBUG, "Registered new agent");
ea3f0419 808 netagent_post_event(registered_uuid, KEV_NETAGENT_REGISTERED, TRUE, false);
5ba3f43e
A
809
810 return 0;
811}
812
39037602
A
813static errno_t
814netagent_handle_register_setopt(struct netagent_session *session, u_int8_t *payload,
0a7de745 815 u_int32_t payload_length)
39037602
A
816{
817 int data_size = 0;
818 struct netagent_wrapper *new_wrapper = NULL;
819 u_int32_t response_error = 0;
820 struct netagent *register_netagent = (struct netagent *)(void *)payload;
ea3f0419 821 uuid_t registered_uuid;
39037602
A
822
823 if (session == NULL) {
824 NETAGENTLOG0(LOG_ERR, "Failed to find session");
825 response_error = EINVAL;
826 goto done;
827 }
828
829 if (payload == NULL) {
830 NETAGENTLOG0(LOG_ERR, "No payload received");
831 response_error = EINVAL;
832 goto done;
833 }
834
835 if (session->wrapper != NULL) {
836 NETAGENTLOG0(LOG_ERR, "Session already has a registered agent");
837 response_error = EINVAL;
838 goto done;
839 }
840
841 if (payload_length < sizeof(struct netagent)) {
a39ff7e2 842 NETAGENTLOG(LOG_ERR, "Register message size too small for agent: (%u < %lu)",
0a7de745 843 payload_length, sizeof(struct netagent));
39037602
A
844 response_error = EINVAL;
845 goto done;
846 }
847
848 data_size = register_netagent->netagent_data_size;
849 if (data_size < 0 || data_size > NETAGENT_MAX_DATA_SIZE) {
00867663 850 NETAGENTLOG(LOG_ERR, "Register message size could not be read, data_size %d", data_size);
39037602
A
851 response_error = EINVAL;
852 goto done;
853 }
854
00867663 855 if (payload_length != (sizeof(struct netagent) + data_size)) {
a39ff7e2 856 NETAGENTLOG(LOG_ERR, "Mismatch between data size and payload length (%lu != %u)", (sizeof(struct netagent) + data_size), payload_length);
00867663
A
857 response_error = EINVAL;
858 goto done;
0a7de745 859 }
00867663 860
39037602
A
861 MALLOC(new_wrapper, struct netagent_wrapper *, sizeof(*new_wrapper) + data_size, M_NETAGENT, M_WAITOK);
862 if (new_wrapper == NULL) {
863 NETAGENTLOG0(LOG_ERR, "Failed to allocate agent");
864 response_error = ENOMEM;
865 goto done;
866 }
867
868 memset(new_wrapper, 0, sizeof(*new_wrapper) + data_size);
cb323159 869 __nochk_memcpy(&new_wrapper->netagent, register_netagent, sizeof(struct netagent) + data_size);
39037602 870
ea3f0419
A
871 uuid_copy(registered_uuid, new_wrapper->netagent.netagent_uuid);
872
39037602
A
873 response_error = netagent_handle_register_inner(session, new_wrapper);
874 if (response_error != 0) {
875 FREE(new_wrapper, M_NETAGENT);
876 goto done;
877 }
878
879 NETAGENTLOG0(LOG_DEBUG, "Registered new agent");
ea3f0419 880 netagent_post_event(registered_uuid, KEV_NETAGENT_REGISTERED, TRUE, false);
39037602
A
881
882done:
883 return response_error;
884}
885
3e170ce0 886static void
39037602 887netagent_handle_register_message(struct netagent_session *session, u_int32_t message_id,
0a7de745 888 u_int32_t payload_length, mbuf_t packet, int offset)
3e170ce0
A
889{
890 int error;
891 int data_size = 0;
892 struct netagent_wrapper *new_wrapper = NULL;
893 u_int32_t response_error = NETAGENT_MESSAGE_ERROR_INTERNAL;
ea3f0419 894 uuid_t registered_uuid;
3e170ce0
A
895
896 if (session == NULL) {
897 NETAGENTLOG0(LOG_ERR, "Failed to find session");
898 response_error = NETAGENT_MESSAGE_ERROR_INTERNAL;
899 goto fail;
900 }
901
902 if (session->wrapper != NULL) {
903 NETAGENTLOG0(LOG_ERR, "Session already has a registered agent");
904 response_error = NETAGENT_MESSAGE_ERROR_ALREADY_REGISTERED;
905 goto fail;
906 }
907
908 if (payload_length < sizeof(struct netagent)) {
a39ff7e2 909 NETAGENTLOG(LOG_ERR, "Register message size too small for agent: (%u < %lu)",
0a7de745 910 payload_length, sizeof(struct netagent));
3e170ce0
A
911 response_error = NETAGENT_MESSAGE_ERROR_INVALID_DATA;
912 goto fail;
913 }
914
915 data_size = netagent_packet_get_netagent_data_size(packet, offset, &error);
916 if (error || data_size < 0 || data_size > NETAGENT_MAX_DATA_SIZE) {
917 NETAGENTLOG(LOG_ERR, "Register message size could not be read, error %d data_size %d",
0a7de745 918 error, data_size);
3e170ce0
A
919 response_error = NETAGENT_MESSAGE_ERROR_INVALID_DATA;
920 goto fail;
921 }
922
923 MALLOC(new_wrapper, struct netagent_wrapper *, sizeof(*new_wrapper) + data_size, M_NETAGENT, M_WAITOK);
924 if (new_wrapper == NULL) {
925 NETAGENTLOG0(LOG_ERR, "Failed to allocate agent");
926 response_error = NETAGENT_MESSAGE_ERROR_INTERNAL;
927 goto fail;
928 }
929
930 memset(new_wrapper, 0, sizeof(*new_wrapper) + data_size);
931
932 error = mbuf_copydata(packet, offset, sizeof(struct netagent) + data_size,
0a7de745 933 &new_wrapper->netagent);
3e170ce0
A
934 if (error) {
935 NETAGENTLOG(LOG_ERR, "Failed to read data into agent structure: %d", error);
936 FREE(new_wrapper, M_NETAGENT);
937 response_error = NETAGENT_MESSAGE_ERROR_INTERNAL;
938 goto fail;
939 }
940
ea3f0419
A
941 uuid_copy(registered_uuid, new_wrapper->netagent.netagent_uuid);
942
943 error = netagent_handle_register_inner(session, new_wrapper);
944 if (error) {
945 NETAGENTLOG(LOG_ERR, "Failed to register agent: %d", error);
946 FREE(new_wrapper, M_NETAGENT);
947 response_error = NETAGENT_MESSAGE_ERROR_INTERNAL;
948 goto fail;
949 }
3e170ce0
A
950
951 NETAGENTLOG0(LOG_DEBUG, "Registered new agent");
952 netagent_send_success_response(session, NETAGENT_MESSAGE_TYPE_REGISTER, message_id);
ea3f0419 953 netagent_post_event(registered_uuid, KEV_NETAGENT_REGISTERED, TRUE, false);
3e170ce0
A
954 return;
955fail:
956 netagent_send_error_response(session, NETAGENT_MESSAGE_TYPE_REGISTER, message_id, response_error);
957}
958
5ba3f43e
A
959errno_t
960netagent_unregister(netagent_session_t _session)
961{
962 struct netagent_session *session = (struct netagent_session *)_session;
963 if (session == NULL) {
964 NETAGENTLOG0(LOG_ERR, "Cannot unregister NULL session");
965 return EINVAL;
966 }
967
968 netagent_unregister_session_wrapper(session);
969 return 0;
970}
971
39037602
A
972static errno_t
973netagent_handle_unregister_setopt(struct netagent_session *session, u_int8_t *payload,
0a7de745 974 u_int32_t payload_length)
39037602
A
975{
976#pragma unused(payload, payload_length)
977 u_int32_t response_error = 0;
978
979 if (session == NULL) {
980 NETAGENTLOG0(LOG_ERR, "Failed to find session");
981 response_error = EINVAL;
982 goto done;
983 }
984
985 netagent_unregister_session_wrapper(session);
986
987done:
988 return response_error;
989}
990
3e170ce0 991static void
39037602 992netagent_handle_unregister_message(struct netagent_session *session, u_int32_t message_id,
0a7de745 993 u_int32_t payload_length, mbuf_t packet, int offset)
3e170ce0
A
994{
995#pragma unused(payload_length, packet, offset)
996 u_int32_t response_error = NETAGENT_MESSAGE_ERROR_INTERNAL;
997
998 if (session == NULL) {
999 NETAGENTLOG0(LOG_ERR, "Failed to find session");
1000 response_error = NETAGENT_MESSAGE_ERROR_INTERNAL;
1001 goto fail;
1002 }
1003
1004 netagent_unregister_session_wrapper(session);
1005
1006 netagent_send_success_response(session, NETAGENT_MESSAGE_TYPE_UNREGISTER, message_id);
1007 return;
1008fail:
1009 netagent_send_error_response(session, NETAGENT_MESSAGE_TYPE_UNREGISTER, message_id, response_error);
1010}
1011
1012static void
39037602 1013netagent_send_cellular_failed_event(struct netagent_wrapper *wrapper,
0a7de745 1014 pid_t pid, uuid_t proc_uuid)
39037602
A
1015{
1016 if (strncmp(wrapper->netagent.netagent_domain, "Cellular", NETAGENT_DOMAINSIZE) != 0) {
1017 return;
1018 }
1019
1020 struct kev_netpolicy_ifdenied ev_ifdenied;
1021
1022 bzero(&ev_ifdenied, sizeof(ev_ifdenied));
1023
1024 ev_ifdenied.ev_data.epid = pid;
1025 uuid_copy(ev_ifdenied.ev_data.euuid, proc_uuid);
1026 ev_ifdenied.ev_if_functional_type = IFRTYPE_FUNCTIONAL_CELLULAR;
1027
1028 netpolicy_post_msg(KEV_NETPOLICY_IFFAILED, &ev_ifdenied.ev_data, sizeof(ev_ifdenied));
1029}
1030
1031static errno_t
1032netagent_handle_update_inner(struct netagent_session *session, struct netagent_wrapper *new_wrapper, u_int32_t data_size, u_int8_t *agent_changed, netagent_error_domain_t error_domain)
1033{
1034 u_int32_t response_error = 0;
1035
1036 if (agent_changed == NULL) {
1037 NETAGENTLOG0(LOG_ERR, "Invalid argument: agent_changed");
1038 return EINVAL;
1039 }
1040
1041 lck_rw_lock_exclusive(&netagent_lock);
1042
1043 if (uuid_compare(session->wrapper->netagent.netagent_uuid, new_wrapper->netagent.netagent_uuid) != 0 ||
0a7de745
A
1044 memcmp(&session->wrapper->netagent.netagent_domain, &new_wrapper->netagent.netagent_domain,
1045 sizeof(new_wrapper->netagent.netagent_domain)) != 0 ||
1046 memcmp(&session->wrapper->netagent.netagent_type, &new_wrapper->netagent.netagent_type,
1047 sizeof(new_wrapper->netagent.netagent_type)) != 0) {
1048 lck_rw_done(&netagent_lock);
1049 NETAGENTLOG0(LOG_ERR, "Basic agent parameters do not match, cannot update");
1050 if (error_domain == kNetagentErrorDomainPOSIX) {
1051 response_error = EINVAL;
1052 } else if (error_domain == kNetagentErrorDomainUserDefined) {
1053 response_error = NETAGENT_MESSAGE_ERROR_CANNOT_UPDATE;
39037602 1054 }
0a7de745
A
1055 return response_error;
1056 }
39037602
A
1057
1058 new_wrapper->netagent.netagent_flags |= NETAGENT_FLAG_REGISTERED;
1059 if (session->wrapper->netagent.netagent_data_size == new_wrapper->netagent.netagent_data_size &&
0a7de745 1060 memcmp(&session->wrapper->netagent, &new_wrapper->netagent, sizeof(struct netagent) + data_size) == 0) {
39037602
A
1061 // Agent is exactly identical, don't increment the generation count
1062
1063 // Make a copy of the list of pending clients, and clear the current list
1064 struct netagent_client_list_s pending_triggers_list_copy;
1065 LIST_INIT(&pending_triggers_list_copy);
1066 struct netagent_client *search_client = NULL;
1067 struct netagent_client *temp_client = NULL;
1068 LIST_FOREACH_SAFE(search_client, &session->wrapper->pending_triggers_list, client_chain, temp_client) {
1069 LIST_REMOVE(search_client, client_chain);
1070 LIST_INSERT_HEAD(&pending_triggers_list_copy, search_client, client_chain);
1071 }
1072 lck_rw_done(&netagent_lock);
1073
1074 // Update pending client triggers without holding a lock
1075 search_client = NULL;
1076 temp_client = NULL;
1077 LIST_FOREACH_SAFE(search_client, &pending_triggers_list_copy, client_chain, temp_client) {
d9a64523 1078 necp_force_update_client(search_client->client_id, session->wrapper->netagent.netagent_uuid, session->wrapper->generation);
39037602
A
1079 netagent_send_cellular_failed_event(new_wrapper, search_client->client_pid, search_client->client_proc_uuid);
1080 LIST_REMOVE(search_client, client_chain);
1081 FREE(search_client, M_NETAGENT);
1082 }
1083 NETAGENTLOG0(LOG_DEBUG, "Updated agent (no changes)");
1084 *agent_changed = FALSE;
1085 return response_error;
1086 }
1087
1088 new_wrapper->generation = g_next_generation++;
813fb2f6 1089 new_wrapper->use_count = session->wrapper->use_count;
39037602
A
1090
1091 if ((new_wrapper->netagent.netagent_flags & NETAGENT_FLAG_ACTIVE) &&
0a7de745 1092 !(session->wrapper->netagent.netagent_flags & NETAGENT_FLAG_ACTIVE)) {
39037602
A
1093 netagent_active_count++;
1094 } else if (!(new_wrapper->netagent.netagent_flags & NETAGENT_FLAG_ACTIVE) &&
0a7de745
A
1095 (session->wrapper->netagent.netagent_flags & NETAGENT_FLAG_ACTIVE) &&
1096 netagent_active_count > 0) {
39037602
A
1097 netagent_active_count--;
1098 }
1099
1100 LIST_REMOVE(session->wrapper, master_chain);
1101 netagent_free_wrapper(session->wrapper);
1102 session->wrapper = new_wrapper;
1103 new_wrapper->control_unit = session->control_unit;
5ba3f43e
A
1104 new_wrapper->event_handler = session->event_handler;
1105 new_wrapper->event_context = session->event_context;
39037602
A
1106 LIST_INSERT_HEAD(&master_netagent_list, new_wrapper, master_chain);
1107 LIST_INIT(&new_wrapper->pending_triggers_list);
1108
1109 NETAGENTLOG0(LOG_DEBUG, "Updated agent");
1110 *agent_changed = TRUE;
1111
1112 lck_rw_done(&netagent_lock);
1113
1114 return response_error;
1115}
1116
5ba3f43e
A
1117errno_t
1118netagent_update(netagent_session_t _session, struct netagent *agent)
1119{
1120 u_int8_t agent_changed;
1121 int data_size = 0;
1122 struct netagent_wrapper *new_wrapper = NULL;
ea3f0419
A
1123 bool should_update_immediately;
1124 uuid_t updated_uuid;
5ba3f43e
A
1125
1126 struct netagent_session *session = (struct netagent_session *)_session;
1127 if (session == NULL) {
1128 NETAGENTLOG0(LOG_ERR, "Cannot update agent on NULL session");
1129 return EINVAL;
1130 }
1131
1132 if (agent == NULL) {
1133 NETAGENTLOG0(LOG_ERR, "Cannot register NULL agent");
1134 return EINVAL;
1135 }
1136
1137 if (session->wrapper == NULL) {
1138 NETAGENTLOG0(LOG_ERR, "Session has no agent to update");
1139 return EINVAL;
1140 }
1141
1142 data_size = agent->netagent_data_size;
1143 if (data_size > NETAGENT_MAX_DATA_SIZE) {
1144 NETAGENTLOG(LOG_ERR, "Update message size (%u > %u) too large", data_size, NETAGENT_MAX_DATA_SIZE);
1145 return EINVAL;
1146 }
1147
1148 MALLOC(new_wrapper, struct netagent_wrapper *, sizeof(*new_wrapper) + data_size, M_NETAGENT, M_WAITOK);
1149 if (new_wrapper == NULL) {
1150 NETAGENTLOG0(LOG_ERR, "Failed to allocate agent");
1151 return ENOMEM;
1152 }
1153
1154 memset(new_wrapper, 0, sizeof(*new_wrapper) + data_size);
cb323159 1155 __nochk_memcpy(&new_wrapper->netagent, agent, sizeof(struct netagent) + data_size);
5ba3f43e 1156
ea3f0419
A
1157 uuid_copy(updated_uuid, new_wrapper->netagent.netagent_uuid);
1158 should_update_immediately = (NETAGENT_FLAG_UPDATE_IMMEDIATELY == (new_wrapper->netagent.netagent_flags & NETAGENT_FLAG_UPDATE_IMMEDIATELY));
1159
5ba3f43e
A
1160 int error = netagent_handle_update_inner(session, new_wrapper, data_size, &agent_changed, kNetagentErrorDomainPOSIX);
1161 if (error == 0) {
ea3f0419 1162 netagent_post_event(updated_uuid, KEV_NETAGENT_UPDATED, agent_changed, should_update_immediately);
5ba3f43e
A
1163 if (agent_changed == FALSE) {
1164 // The session wrapper does not need the "new_wrapper" as nothing changed
1165 FREE(new_wrapper, M_NETAGENT);
1166 }
1167 } else {
1168 FREE(new_wrapper, M_NETAGENT);
1169 return error;
1170 }
1171
1172 return 0;
1173}
1174
39037602
A
1175static errno_t
1176netagent_handle_update_setopt(struct netagent_session *session, u_int8_t *payload, u_int32_t payload_length)
1177{
1178 u_int32_t data_size = 0;
1179 struct netagent_wrapper *new_wrapper = NULL;
1180 errno_t response_error = 0;
1181 struct netagent *update_netagent = (struct netagent *)(void *)payload;
1182 u_int8_t agent_changed;
ea3f0419
A
1183 bool should_update_immediately;
1184 uuid_t updated_uuid;
39037602
A
1185
1186 if (session == NULL) {
1187 NETAGENTLOG0(LOG_ERR, "Failed to find session");
1188 response_error = EINVAL;
1189 goto done;
1190 }
1191
1192 if (payload == NULL) {
1193 NETAGENTLOG0(LOG_ERR, "No payload received");
1194 response_error = EINVAL;
1195 goto done;
1196 }
1197
1198 if (session->wrapper == NULL) {
1199 NETAGENTLOG0(LOG_ERR, "Session has no agent to update");
1200 response_error = ENOENT;
1201 goto done;
1202 }
1203
1204 if (payload_length < sizeof(struct netagent)) {
a39ff7e2 1205 NETAGENTLOG(LOG_ERR, "Update message size too small for agent: (%u < %lu)",
0a7de745 1206 payload_length, sizeof(struct netagent));
39037602
A
1207 response_error = EINVAL;
1208 goto done;
1209 }
1210
1211 data_size = update_netagent->netagent_data_size;
1212 if (data_size > NETAGENT_MAX_DATA_SIZE) {
1213 NETAGENTLOG(LOG_ERR, "Update message size (%u > %u) too large", data_size, NETAGENT_MAX_DATA_SIZE);
1214 response_error = EINVAL;
1215 goto done;
1216 }
1217
00867663 1218 if (payload_length != (sizeof(struct netagent) + data_size)) {
a39ff7e2 1219 NETAGENTLOG(LOG_ERR, "Mismatch between data size and payload length (%lu != %u)", (sizeof(struct netagent) + data_size), payload_length);
00867663
A
1220 response_error = EINVAL;
1221 goto done;
0a7de745 1222 }
00867663 1223
39037602
A
1224 MALLOC(new_wrapper, struct netagent_wrapper *, sizeof(*new_wrapper) + data_size, M_NETAGENT, M_WAITOK);
1225 if (new_wrapper == NULL) {
1226 NETAGENTLOG0(LOG_ERR, "Failed to allocate agent");
1227 response_error = ENOMEM;
1228 goto done;
1229 }
1230
1231 memset(new_wrapper, 0, sizeof(*new_wrapper) + data_size);
cb323159 1232 __nochk_memcpy(&new_wrapper->netagent, update_netagent, sizeof(struct netagent) + data_size);
39037602 1233
ea3f0419
A
1234 uuid_copy(updated_uuid, new_wrapper->netagent.netagent_uuid);
1235 should_update_immediately = (NETAGENT_FLAG_UPDATE_IMMEDIATELY == (new_wrapper->netagent.netagent_flags & NETAGENT_FLAG_UPDATE_IMMEDIATELY));
1236
39037602
A
1237 response_error = netagent_handle_update_inner(session, new_wrapper, data_size, &agent_changed, kNetagentErrorDomainPOSIX);
1238 if (response_error == 0) {
ea3f0419 1239 netagent_post_event(updated_uuid, KEV_NETAGENT_UPDATED, agent_changed, should_update_immediately);
39037602
A
1240 if (agent_changed == FALSE) {
1241 // The session wrapper does not need the "new_wrapper" as nothing changed
1242 FREE(new_wrapper, M_NETAGENT);
1243 }
1244 } else {
1245 FREE(new_wrapper, M_NETAGENT);
1246 }
1247
1248done:
1249 return response_error;
1250}
1251
1252static void
1253netagent_handle_update_message(struct netagent_session *session, u_int32_t message_id,
0a7de745 1254 u_int32_t payload_length, mbuf_t packet, int offset)
3e170ce0
A
1255{
1256 int error;
1257 int data_size = 0;
1258 struct netagent_wrapper *new_wrapper = NULL;
1259 u_int32_t response_error = NETAGENT_MESSAGE_ERROR_INTERNAL;
39037602 1260 u_int8_t agent_changed;
ea3f0419
A
1261 uuid_t updated_uuid;
1262 bool should_update_immediately;
3e170ce0
A
1263
1264 if (session == NULL) {
1265 NETAGENTLOG0(LOG_ERR, "Failed to find session");
1266 response_error = NETAGENT_MESSAGE_ERROR_INTERNAL;
1267 goto fail;
1268 }
1269
1270 if (session->wrapper == NULL) {
1271 NETAGENTLOG0(LOG_ERR, "Session has no agent to update");
1272 response_error = NETAGENT_MESSAGE_ERROR_NOT_REGISTERED;
1273 goto fail;
1274 }
1275
1276 if (payload_length < sizeof(struct netagent)) {
a39ff7e2 1277 NETAGENTLOG(LOG_ERR, "Update message size too small for agent: (%u < %lu)",
0a7de745 1278 payload_length, sizeof(struct netagent));
3e170ce0
A
1279 response_error = NETAGENT_MESSAGE_ERROR_INVALID_DATA;
1280 goto fail;
1281 }
1282
1283 data_size = netagent_packet_get_netagent_data_size(packet, offset, &error);
1284 if (error || data_size < 0 || data_size > NETAGENT_MAX_DATA_SIZE) {
1285 NETAGENTLOG(LOG_ERR, "Update message size could not be read, error %d data_size %d",
0a7de745 1286 error, data_size);
3e170ce0
A
1287 response_error = NETAGENT_MESSAGE_ERROR_INVALID_DATA;
1288 goto fail;
1289 }
1290
1291 MALLOC(new_wrapper, struct netagent_wrapper *, sizeof(*new_wrapper) + data_size, M_NETAGENT, M_WAITOK);
1292 if (new_wrapper == NULL) {
1293 NETAGENTLOG0(LOG_ERR, "Failed to allocate agent");
1294 response_error = NETAGENT_MESSAGE_ERROR_INTERNAL;
1295 goto fail;
1296 }
1297
1298 memset(new_wrapper, 0, sizeof(*new_wrapper) + data_size);
1299
1300 error = mbuf_copydata(packet, offset, sizeof(struct netagent) + data_size, &new_wrapper->netagent);
1301 if (error) {
1302 NETAGENTLOG(LOG_ERR, "Failed to read data into agent structure: %d", error);
1303 FREE(new_wrapper, M_NETAGENT);
1304 response_error = NETAGENT_MESSAGE_ERROR_INTERNAL;
1305 goto fail;
1306 }
1307
ea3f0419
A
1308 uuid_copy(updated_uuid, new_wrapper->netagent.netagent_uuid);
1309 should_update_immediately = (NETAGENT_FLAG_UPDATE_IMMEDIATELY == (new_wrapper->netagent.netagent_flags & NETAGENT_FLAG_UPDATE_IMMEDIATELY));
1310
0a7de745 1311 response_error = netagent_handle_update_inner(session, new_wrapper, data_size, &agent_changed, kNetagentErrorDomainUserDefined);
39037602 1312 if (response_error != 0) {
3e170ce0 1313 FREE(new_wrapper, M_NETAGENT);
3e170ce0
A
1314 goto fail;
1315 }
1316
39037602 1317 netagent_send_success_response(session, NETAGENT_MESSAGE_TYPE_UPDATE, message_id);
ea3f0419 1318 netagent_post_event(updated_uuid, KEV_NETAGENT_UPDATED, agent_changed, should_update_immediately);
3e170ce0 1319
39037602
A
1320 if (agent_changed == FALSE) {
1321 // The session wrapper does not need the "new_wrapper" as nothing changed
1322 FREE(new_wrapper, M_NETAGENT);
1323 }
3e170ce0 1324
3e170ce0
A
1325 return;
1326fail:
1327 netagent_send_error_response(session, NETAGENT_MESSAGE_TYPE_UPDATE, message_id, response_error);
1328}
1329
1330static void
1331netagent_handle_get(struct netagent_session *session, u_int32_t message_id,
0a7de745 1332 u_int32_t payload_length, mbuf_t packet, int offset)
3e170ce0
A
1333{
1334#pragma unused(payload_length, packet, offset)
1335 u_int8_t *response = NULL;
1336 u_int8_t *cursor = NULL;
1337 u_int32_t response_error = NETAGENT_MESSAGE_ERROR_INTERNAL;
1338
1339 if (session == NULL) {
1340 NETAGENTLOG0(LOG_ERR, "Failed to find session");
1341 response_error = NETAGENT_MESSAGE_ERROR_INTERNAL;
1342 goto fail;
1343 }
1344
1345 if (session->wrapper == NULL) {
1346 NETAGENTLOG0(LOG_ERR, "Session has no agent to get");
1347 response_error = NETAGENT_MESSAGE_ERROR_NOT_REGISTERED;
1348 goto fail;
1349 }
1350
1351 lck_rw_lock_shared(&netagent_lock);
1352
1353 size_t response_size = sizeof(struct netagent_message_header) + sizeof(session->wrapper->netagent)
0a7de745 1354 + session->wrapper->netagent.netagent_data_size;
3e170ce0
A
1355 MALLOC(response, u_int8_t *, response_size, M_NETAGENT, M_WAITOK);
1356 if (response == NULL) {
1357 goto fail;
1358 }
1359
1360 cursor = response;
1361 cursor = netagent_buffer_write_message_header(cursor, NETAGENT_MESSAGE_TYPE_GET,
0a7de745
A
1362 NETAGENT_MESSAGE_FLAGS_RESPONSE, message_id, 0,
1363 response_size - sizeof(struct netagent_message_header));
3e170ce0 1364 memcpy(cursor, &session->wrapper->netagent, sizeof(session->wrapper->netagent) +
0a7de745 1365 session->wrapper->netagent.netagent_data_size);
3e170ce0
A
1366
1367 lck_rw_done(&netagent_lock);
1368
1369 if (!netagent_send_ctl_data(session->control_unit, (u_int8_t *)response, response_size)) {
1370 NETAGENTLOG0(LOG_ERR, "Failed to send response");
1371 }
1372 FREE(response, M_NETAGENT);
1373 return;
1374fail:
1375 netagent_send_error_response(session, NETAGENT_MESSAGE_TYPE_GET, message_id, response_error);
1376}
1377
5ba3f43e
A
1378errno_t
1379netagent_assign_nexus(netagent_session_t _session, uuid_t necp_client_uuid,
0a7de745 1380 void *assign_message, size_t assigned_results_length)
5ba3f43e
A
1381{
1382 struct netagent_session *session = (struct netagent_session *)_session;
1383 if (session == NULL) {
1384 NETAGENTLOG0(LOG_ERR, "Cannot assign nexus from NULL session");
1385 return EINVAL;
1386 }
1387
1388 if (session->wrapper == NULL) {
1389 NETAGENTLOG0(LOG_ERR, "Session has no agent");
1390 return ENOENT;
1391 }
1392
1393 // Note that if the error is 0, NECP has taken over our malloc'ed buffer
1394 int error = necp_assign_client_result(session->wrapper->netagent.netagent_uuid, necp_client_uuid, assign_message, assigned_results_length);
1395 if (error) {
1396 // necp_assign_client_result returns POSIX errors; don't error for ENOENT
1397 NETAGENTLOG((error == ENOENT ? LOG_DEBUG : LOG_ERR), "Client assignment failed: %d", error);
1398 return error;
1399 }
1400
1401 NETAGENTLOG0(LOG_DEBUG, "Agent assigned nexus properties to client");
1402 return 0;
1403}
1404
1405errno_t
1406netagent_update_flow_protoctl_event(netagent_session_t _session,
1407 uuid_t client_id, uint32_t protoctl_event_code,
1408 uint32_t protoctl_event_val, uint32_t protoctl_event_tcp_seq_number)
1409{
1410 struct netagent_session *session = (struct netagent_session *)_session;
1411 int error = 0;
1412
1413 if (session == NULL) {
1414 NETAGENTLOG0(LOG_ERR, "Cannot assign nexus from NULL session");
0a7de745 1415 return EINVAL;
5ba3f43e
A
1416 }
1417
1418 if (session->wrapper == NULL) {
1419 NETAGENTLOG0(LOG_ERR, "Session has no agent");
0a7de745 1420 return ENOENT;
5ba3f43e
A
1421 }
1422
1423 error = necp_update_flow_protoctl_event(session->wrapper->netagent.netagent_uuid,
1424 client_id, protoctl_event_code, protoctl_event_val, protoctl_event_tcp_seq_number);
1425
0a7de745 1426 return error;
5ba3f43e
A
1427}
1428
39037602
A
1429static errno_t
1430netagent_handle_assign_nexus_setopt(struct netagent_session *session, u_int8_t *payload,
0a7de745 1431 u_int32_t payload_length)
3e170ce0 1432{
39037602
A
1433 errno_t response_error = 0;
1434 struct netagent_assign_nexus_message *assign_nexus_netagent = (struct netagent_assign_nexus_message *)(void *)payload;
1435 uuid_t client_id;
1436 u_int8_t *assigned_results = NULL;
3e170ce0
A
1437
1438 if (session == NULL) {
1439 NETAGENTLOG0(LOG_ERR, "Failed to find session");
39037602
A
1440 response_error = ENOENT;
1441 goto done;
3e170ce0
A
1442 }
1443
39037602
A
1444 if (payload == NULL) {
1445 NETAGENTLOG0(LOG_ERR, "No payload received");
1446 response_error = EINVAL;
1447 goto done;
3e170ce0
A
1448 }
1449
39037602
A
1450 if (session->wrapper == NULL) {
1451 NETAGENTLOG0(LOG_ERR, "Session has no agent to get");
1452 response_error = ENOENT;
1453 goto done;
3e170ce0
A
1454 }
1455
39037602
A
1456 if (payload_length < sizeof(uuid_t)) {
1457 NETAGENTLOG0(LOG_ERR, "Assign message is too short");
1458 response_error = EINVAL;
1459 goto done;
3e170ce0
A
1460 }
1461
39037602
A
1462 memcpy(client_id, assign_nexus_netagent->assign_client_id, sizeof(client_id));
1463 size_t assigned_results_length = (payload_length - sizeof(client_id));
3e170ce0 1464
39037602
A
1465 if (assigned_results_length > 0) {
1466 MALLOC(assigned_results, u_int8_t *, assigned_results_length, M_NETAGENT, M_WAITOK);
1467 if (assigned_results == NULL) {
1468 NETAGENTLOG(LOG_ERR, "Failed to allocate assign message (%lu bytes)", assigned_results_length);
1469 response_error = ENOMEM;
1470 goto done;
1471 }
1472 memcpy(assigned_results, assign_nexus_netagent->assign_necp_results, assigned_results_length);
3e170ce0
A
1473 }
1474
39037602
A
1475 // Note that if the error is 0, NECP has taken over our malloc'ed buffer
1476 response_error = necp_assign_client_result(session->wrapper->netagent.netagent_uuid, client_id, assigned_results, assigned_results_length);
1477 if (response_error) {
1478 // necp_assign_client_result returns POSIX errors
1479 if (assigned_results) {
1480 FREE(assigned_results, M_NETAGENT);
1481 }
1482 NETAGENTLOG(LOG_ERR, "Client assignment failed: %d", response_error);
1483 goto done;
3e170ce0
A
1484 }
1485
39037602
A
1486 NETAGENTLOG0(LOG_DEBUG, "Agent assigned nexus properties to client");
1487done:
1488 return response_error;
3e170ce0
A
1489}
1490
39037602 1491
3e170ce0 1492static void
39037602 1493netagent_handle_assign_nexus_message(struct netagent_session *session, u_int32_t message_id,
0a7de745 1494 u_int32_t payload_length, mbuf_t packet, int offset)
3e170ce0 1495{
39037602 1496 int error = 0;
3e170ce0 1497 u_int32_t response_error = NETAGENT_MESSAGE_ERROR_INTERNAL;
39037602
A
1498 uuid_t client_id;
1499 u_int8_t *assigned_results = NULL;
3e170ce0
A
1500
1501 if (session == NULL) {
1502 NETAGENTLOG0(LOG_ERR, "Failed to find session");
1503 response_error = NETAGENT_MESSAGE_ERROR_INTERNAL;
1504 goto fail;
1505 }
1506
39037602
A
1507 if (session->wrapper == NULL) {
1508 NETAGENTLOG0(LOG_ERR, "Session has no agent to get");
1509 response_error = NETAGENT_MESSAGE_ERROR_NOT_REGISTERED;
1510 goto fail;
1511 }
1512
3e170ce0 1513 if (payload_length < sizeof(uuid_t)) {
39037602 1514 NETAGENTLOG0(LOG_ERR, "Assign message is too short");
3e170ce0
A
1515 response_error = NETAGENT_MESSAGE_ERROR_INVALID_DATA;
1516 goto fail;
1517 }
1518
39037602 1519 error = mbuf_copydata(packet, offset, sizeof(client_id), &client_id);
3e170ce0 1520 if (error) {
39037602 1521 NETAGENTLOG(LOG_ERR, "Failed to read uuid for assign message: %d", error);
3e170ce0
A
1522 response_error = NETAGENT_MESSAGE_ERROR_INTERNAL;
1523 goto fail;
1524 }
1525
39037602
A
1526 size_t assigned_results_length = (payload_length - sizeof(client_id));
1527 if (assigned_results_length > 0) {
1528 MALLOC(assigned_results, u_int8_t *, assigned_results_length, M_NETAGENT, M_WAITOK);
1529 if (assigned_results == NULL) {
1530 NETAGENTLOG(LOG_ERR, "Failed to allocate assign message (%lu bytes)", assigned_results_length);
1531 response_error = NETAGENT_MESSAGE_ERROR_INTERNAL;
1532 goto fail;
3e170ce0 1533 }
3e170ce0 1534
39037602
A
1535 error = mbuf_copydata(packet, offset + sizeof(client_id), assigned_results_length, assigned_results);
1536 if (error) {
1537 FREE(assigned_results, M_NETAGENT);
1538 NETAGENTLOG(LOG_ERR, "Failed to read assign message: %d", error);
1539 response_error = NETAGENT_MESSAGE_ERROR_INTERNAL;
1540 goto fail;
1541 }
3e170ce0
A
1542 }
1543
39037602
A
1544 // Note that if the error is 0, NECP has taken over our malloc'ed buffer
1545 error = necp_assign_client_result(session->wrapper->netagent.netagent_uuid, client_id, assigned_results, assigned_results_length);
3e170ce0 1546 if (error) {
39037602
A
1547 if (assigned_results) {
1548 FREE(assigned_results, M_NETAGENT);
1549 }
1550 NETAGENTLOG(LOG_ERR, "Client assignment failed: %d", error);
1551 response_error = NETAGENT_MESSAGE_ERROR_CANNOT_ASSIGN;
3e170ce0
A
1552 goto fail;
1553 }
1554
39037602
A
1555 NETAGENTLOG0(LOG_DEBUG, "Agent assigned nexus properties to client");
1556 netagent_send_success_response(session, NETAGENT_MESSAGE_TYPE_ASSIGN_NEXUS, message_id);
3e170ce0
A
1557 return;
1558fail:
39037602 1559 netagent_send_error_response(session, NETAGENT_MESSAGE_TYPE_ASSIGN_NEXUS, message_id, response_error);
3e170ce0
A
1560}
1561
813fb2f6
A
1562errno_t
1563netagent_handle_use_count_setopt(struct netagent_session *session, u_int8_t *payload, size_t payload_length)
1564{
1565 errno_t response_error = 0;
1566 uint64_t use_count = 0;
1567
1568 if (session == NULL) {
1569 NETAGENTLOG0(LOG_ERR, "Failed to find session");
1570 response_error = ENOENT;
1571 goto done;
1572 }
1573
1574 if (payload == NULL) {
1575 NETAGENTLOG0(LOG_ERR, "No payload received");
1576 response_error = EINVAL;
1577 goto done;
1578 }
1579
1580 if (payload_length != sizeof(use_count)) {
a39ff7e2 1581 NETAGENTLOG(LOG_ERR, "Payload length is invalid (%lu)", payload_length);
813fb2f6
A
1582 response_error = EINVAL;
1583 goto done;
1584 }
1585
1586 memcpy(&use_count, payload, sizeof(use_count));
1587
1588 lck_rw_lock_shared(&netagent_lock);
1589
1590 if (session->wrapper == NULL) {
1591 NETAGENTLOG0(LOG_ERR, "Session has no agent registered");
1592 response_error = ENOENT;
1593 lck_rw_done(&netagent_lock);
1594 goto done;
1595 }
1596
1597 session->wrapper->use_count = use_count;
1598
1599 lck_rw_done(&netagent_lock);
1600
1601done:
1602 return response_error;
1603}
1604
1605errno_t
1606netagent_handle_use_count_getopt(struct netagent_session *session, u_int8_t *buffer, size_t *buffer_length)
1607{
1608 errno_t response_error = 0;
1609 uint64_t use_count = 0;
1610
1611 if (session == NULL) {
1612 NETAGENTLOG0(LOG_ERR, "Failed to find session");
1613 response_error = ENOENT;
1614 goto done;
1615 }
1616
1617 if (buffer == NULL) {
1618 NETAGENTLOG0(LOG_ERR, "No payload received");
1619 response_error = EINVAL;
1620 goto done;
1621 }
1622
1623 if (*buffer_length != sizeof(use_count)) {
a39ff7e2 1624 NETAGENTLOG(LOG_ERR, "Buffer length is invalid (%lu)", *buffer_length);
813fb2f6
A
1625 response_error = EINVAL;
1626 goto done;
1627 }
1628
1629 lck_rw_lock_shared(&netagent_lock);
1630
1631 if (session->wrapper == NULL) {
1632 NETAGENTLOG0(LOG_ERR, "Session has no agent registered");
1633 response_error = ENOENT;
1634 lck_rw_done(&netagent_lock);
1635 goto done;
1636 }
1637
1638 use_count = session->wrapper->use_count;
1639 lck_rw_done(&netagent_lock);
1640
1641 memcpy(buffer, &use_count, sizeof(use_count));
1642 *buffer_length = sizeof(use_count);
1643
1644done:
1645 return response_error;
1646}
1647
3e170ce0
A
1648static struct netagent_wrapper *
1649netagent_find_agent_with_uuid(uuid_t uuid)
1650{
1651 struct netagent_wrapper *search_netagent = NULL;
1652
1653 LIST_FOREACH(search_netagent, &master_netagent_list, master_chain) {
1654 if (uuid_compare(search_netagent->netagent.netagent_uuid, uuid) == 0) {
0a7de745 1655 return search_netagent;
3e170ce0
A
1656 }
1657 }
1658
0a7de745 1659 return NULL;
3e170ce0
A
1660}
1661
1662void
1663netagent_post_updated_interfaces(uuid_t uuid)
1664{
1665 struct netagent_wrapper *wrapper = NULL;
1666 lck_rw_lock_shared(&netagent_lock);
1667 wrapper = netagent_find_agent_with_uuid(uuid);
1668 lck_rw_done(&netagent_lock);
1669
1670 if (wrapper != NULL) {
cb323159 1671 netagent_post_event(uuid, KEV_NETAGENT_UPDATED_INTERFACES, TRUE, false);
3e170ce0
A
1672 } else {
1673 NETAGENTLOG0(LOG_DEBUG, "Interface event with no associated agent");
1674 }
1675
1676 return;
1677}
1678
39037602
A
1679static u_int32_t
1680netagent_dump_get_data_size_locked()
1681{
1682 struct netagent_wrapper *search_netagent = NULL;
1683 u_int32_t total_netagent_data_size = 0;
1684 // Traverse the master list to know how much data the client needs to allocate to get the list of agent UUIDs
1685 LIST_FOREACH(search_netagent, &master_netagent_list, master_chain) {
1686 total_netagent_data_size += sizeof(search_netagent->netagent.netagent_uuid);
1687 }
1688 return total_netagent_data_size;
1689}
1690
1691static void
1692netagent_dump_copy_data_locked(u_int8_t *buffer, u_int32_t buffer_length)
1693{
1694 size_t response_size = 0;
1695 u_int8_t *cursor = NULL;
1696 struct netagent_wrapper *search_netagent = NULL;
1697
1698 response_size = buffer_length; // We already know that buffer_length is the same as total_netagent_data_size.
1699 cursor = buffer;
1700 LIST_FOREACH(search_netagent, &master_netagent_list, master_chain) {
1701 memcpy(cursor, search_netagent->netagent.netagent_uuid, sizeof(search_netagent->netagent.netagent_uuid));
1702 cursor += sizeof(search_netagent->netagent.netagent_uuid);
1703 }
1704}
1705
3e170ce0
A
1706int
1707netagent_ioctl(u_long cmd, caddr_t data)
1708{
1709 int error = 0;
1710
39037602 1711 switch (cmd) {
0a7de745
A
1712 case SIOCGIFAGENTLIST32:
1713 case SIOCGIFAGENTLIST64: {
1714 /* Check entitlement if the client requests agent dump */
1715 errno_t cred_result = priv_check_cred(kauth_cred_get(), PRIV_NET_PRIVILEGED_NECP_POLICIES, 0);
1716 if (cred_result != 0) {
1717 NETAGENTLOG0(LOG_ERR, "Client does not hold the necessary entitlement to get netagent information");
1718 return EINVAL;
39037602 1719 }
0a7de745
A
1720 break;
1721 }
1722 default:
1723 break;
39037602
A
1724 }
1725
3e170ce0
A
1726 lck_rw_lock_shared(&netagent_lock);
1727 switch (cmd) {
0a7de745
A
1728 case SIOCGIFAGENTDATA32: {
1729 struct netagent_req32 *ifsir32 = (struct netagent_req32 *)(void *)data;
1730 struct netagent_wrapper *wrapper = netagent_find_agent_with_uuid(ifsir32->netagent_uuid);
1731 if (wrapper == NULL) {
1732 error = ENOENT;
3e170ce0
A
1733 break;
1734 }
0a7de745
A
1735 uuid_copy(ifsir32->netagent_uuid, wrapper->netagent.netagent_uuid);
1736 memcpy(ifsir32->netagent_domain, wrapper->netagent.netagent_domain, sizeof(ifsir32->netagent_domain));
1737 memcpy(ifsir32->netagent_type, wrapper->netagent.netagent_type, sizeof(ifsir32->netagent_type));
1738 memcpy(ifsir32->netagent_desc, wrapper->netagent.netagent_desc, sizeof(ifsir32->netagent_desc));
1739 ifsir32->netagent_flags = wrapper->netagent.netagent_flags;
1740 if (ifsir32->netagent_data_size == 0) {
1741 // First pass, client wants data size
1742 ifsir32->netagent_data_size = wrapper->netagent.netagent_data_size;
1743 } else if (ifsir32->netagent_data != USER_ADDR_NULL &&
1744 ifsir32->netagent_data_size == wrapper->netagent.netagent_data_size) {
1745 // Second pass, client wants data buffer filled out
1746 error = copyout(wrapper->netagent.netagent_data, ifsir32->netagent_data, wrapper->netagent.netagent_data_size);
1747 } else {
1748 error = EINVAL;
3e170ce0 1749 }
0a7de745
A
1750 break;
1751 }
1752 case SIOCGIFAGENTDATA64: {
1753 struct netagent_req64 *ifsir64 = (struct netagent_req64 *)(void *)data;
1754 struct netagent_wrapper *wrapper = netagent_find_agent_with_uuid(ifsir64->netagent_uuid);
1755 if (wrapper == NULL) {
1756 error = ENOENT;
39037602
A
1757 break;
1758 }
0a7de745
A
1759 uuid_copy(ifsir64->netagent_uuid, wrapper->netagent.netagent_uuid);
1760 memcpy(ifsir64->netagent_domain, wrapper->netagent.netagent_domain, sizeof(ifsir64->netagent_domain));
1761 memcpy(ifsir64->netagent_type, wrapper->netagent.netagent_type, sizeof(ifsir64->netagent_type));
1762 memcpy(ifsir64->netagent_desc, wrapper->netagent.netagent_desc, sizeof(ifsir64->netagent_desc));
1763 ifsir64->netagent_flags = wrapper->netagent.netagent_flags;
1764 if (ifsir64->netagent_data_size == 0) {
1765 // First pass, client wants data size
1766 ifsir64->netagent_data_size = wrapper->netagent.netagent_data_size;
1767 } else if (ifsir64->netagent_data != USER_ADDR_NULL &&
1768 ifsir64->netagent_data_size == wrapper->netagent.netagent_data_size) {
1769 // Second pass, client wants data buffer filled out
1770 error = copyout(wrapper->netagent.netagent_data, ifsir64->netagent_data, wrapper->netagent.netagent_data_size);
1771 } else {
1772 error = EINVAL;
1773 }
1774 break;
1775 }
1776 case SIOCGIFAGENTLIST32: {
1777 struct netagentlist_req32 *ifsir32 = (struct netagentlist_req32 *)(void *)data;
1778 if (ifsir32->data_size == 0) {
1779 // First pass, client wants data size
1780 ifsir32->data_size = netagent_dump_get_data_size_locked();
1781 } else if (ifsir32->data != USER_ADDR_NULL &&
1782 ifsir32->data_size > 0 &&
1783 ifsir32->data_size == netagent_dump_get_data_size_locked()) {
1784 // Second pass, client wants data buffer filled out
1785 u_int8_t *response = NULL;
1786 MALLOC(response, u_int8_t *, ifsir32->data_size, M_NETAGENT, M_NOWAIT | M_ZERO);
1787 if (response == NULL) {
1788 error = ENOMEM;
1789 break;
39037602 1790 }
0a7de745
A
1791
1792 netagent_dump_copy_data_locked(response, ifsir32->data_size);
1793 error = copyout(response, ifsir32->data, ifsir32->data_size);
1794 FREE(response, M_NETAGENT);
1795 } else {
1796 error = EINVAL;
39037602 1797 }
0a7de745
A
1798 break;
1799 }
1800 case SIOCGIFAGENTLIST64: {
1801 struct netagentlist_req64 *ifsir64 = (struct netagentlist_req64 *)(void *)data;
1802 if (ifsir64->data_size == 0) {
1803 // First pass, client wants data size
1804 ifsir64->data_size = netagent_dump_get_data_size_locked();
1805 } else if (ifsir64->data != USER_ADDR_NULL &&
1806 ifsir64->data_size > 0 &&
1807 ifsir64->data_size == netagent_dump_get_data_size_locked()) {
1808 // Second pass, client wants data buffer filled out
1809 u_int8_t *response = NULL;
1810 MALLOC(response, u_int8_t *, ifsir64->data_size, M_NETAGENT, M_NOWAIT | M_ZERO);
1811 if (response == NULL) {
1812 error = ENOMEM;
1813 break;
1814 }
1815
1816 netagent_dump_copy_data_locked(response, ifsir64->data_size);
1817 error = copyout(response, ifsir64->data, ifsir64->data_size);
1818 FREE(response, M_NETAGENT);
1819 } else {
3e170ce0 1820 error = EINVAL;
3e170ce0 1821 }
0a7de745
A
1822 break;
1823 }
1824 default: {
1825 error = EINVAL;
1826 break;
1827 }
3e170ce0
A
1828 }
1829 lck_rw_done(&netagent_lock);
0a7de745 1830 return error;
3e170ce0
A
1831}
1832
1833u_int32_t
1834netagent_get_flags(uuid_t uuid)
1835{
1836 u_int32_t flags = 0;
1837 lck_rw_lock_shared(&netagent_lock);
1838 struct netagent_wrapper *wrapper = netagent_find_agent_with_uuid(uuid);
1839 if (wrapper != NULL) {
1840 flags = wrapper->netagent.netagent_flags;
1841 } else {
1842 NETAGENTLOG0(LOG_DEBUG, "Flags requested for invalid netagent");
1843 }
1844 lck_rw_done(&netagent_lock);
1845
0a7de745 1846 return flags;
3e170ce0
A
1847}
1848
cb323159
A
1849errno_t
1850netagent_set_flags(uuid_t uuid, u_int32_t flags)
1851{
1852 errno_t error = 0;
1853 lck_rw_lock_exclusive(&netagent_lock);
1854 struct netagent_wrapper *wrapper = netagent_find_agent_with_uuid(uuid);
1855 if (wrapper != NULL) {
1856 wrapper->netagent.netagent_flags = flags;
1857 } else {
1858 NETAGENTLOG0(LOG_DEBUG,
1859 "Attempt to set flags for invalid netagent");
1860 error = ENOENT;
1861 }
1862 lck_rw_done(&netagent_lock);
1863
1864 return error;
1865}
1866
39037602
A
1867u_int32_t
1868netagent_get_generation(uuid_t uuid)
1869{
1870 u_int32_t generation = 0;
1871 lck_rw_lock_shared(&netagent_lock);
1872 struct netagent_wrapper *wrapper = netagent_find_agent_with_uuid(uuid);
1873 if (wrapper != NULL) {
1874 generation = wrapper->generation;
1875 } else {
1876 NETAGENTLOG0(LOG_DEBUG, "Generation requested for invalid netagent");
1877 }
1878 lck_rw_done(&netagent_lock);
1879
0a7de745 1880 return generation;
39037602
A
1881}
1882
1883bool
1884netagent_get_agent_domain_and_type(uuid_t uuid, char *domain, char *type)
1885{
1886 bool found = FALSE;
1887 if (domain == NULL || type == NULL) {
1888 NETAGENTLOG(LOG_ERR, "Invalid arguments for netagent_get_agent_domain_and_type %p %p", domain, type);
0a7de745 1889 return FALSE;
39037602
A
1890 }
1891
1892 lck_rw_lock_shared(&netagent_lock);
1893 struct netagent_wrapper *wrapper = netagent_find_agent_with_uuid(uuid);
1894 if (wrapper != NULL) {
1895 found = TRUE;
1896 memcpy(domain, wrapper->netagent.netagent_domain, NETAGENT_DOMAINSIZE);
1897 memcpy(type, wrapper->netagent.netagent_type, NETAGENT_TYPESIZE);
1898 } else {
d9a64523 1899 NETAGENTLOG0(LOG_ERR, "Type requested for invalid netagent");
39037602
A
1900 }
1901 lck_rw_done(&netagent_lock);
1902
0a7de745 1903 return found;
39037602
A
1904}
1905
3e170ce0
A
1906int
1907netagent_kernel_trigger(uuid_t uuid)
1908{
1909 int error = 0;
1910
1911 lck_rw_lock_shared(&netagent_lock);
1912 struct netagent_wrapper *wrapper = netagent_find_agent_with_uuid(uuid);
1913 if (wrapper == NULL) {
1914 NETAGENTLOG0(LOG_ERR, "Requested netagent for kernel trigger could not be found");
1915 error = ENOENT;
1916 goto done;
1917 }
1918
1919 if ((wrapper->netagent.netagent_flags & NETAGENT_FLAG_KERNEL_ACTIVATED) == 0) {
1920 NETAGENTLOG0(LOG_ERR, "Requested netagent for kernel trigger is not kernel activated");
1921 // Agent does not accept kernel triggers
1922 error = EINVAL;
1923 goto done;
1924 }
1925
1926 if ((wrapper->netagent.netagent_flags & NETAGENT_FLAG_ACTIVE)) {
1927 // Agent already active
1928 NETAGENTLOG0(LOG_INFO, "Requested netagent for kernel trigger is already active");
1929 error = 0;
1930 goto done;
1931 }
1932
1933 error = netagent_send_trigger(wrapper, current_proc(), NETAGENT_TRIGGER_FLAG_KERNEL, NETAGENT_MESSAGE_TYPE_TRIGGER);
1934 NETAGENTLOG((error ? LOG_ERR : LOG_INFO), "Triggered netagent from kernel (error %d)", error);
1935done:
1936 lck_rw_done(&netagent_lock);
0a7de745 1937 return error;
3e170ce0
A
1938}
1939
39037602 1940int
5ba3f43e 1941netagent_client_message_with_params(uuid_t agent_uuid,
0a7de745
A
1942 uuid_t necp_client_uuid,
1943 pid_t pid,
1944 void *handle,
1945 u_int8_t message_type,
cb323159 1946 struct necp_client_agent_parameters *parameters,
0a7de745
A
1947 void **assigned_results,
1948 size_t *assigned_results_length)
39037602
A
1949{
1950 int error = 0;
1951
1952 if (message_type != NETAGENT_MESSAGE_TYPE_CLIENT_TRIGGER &&
0a7de745
A
1953 message_type != NETAGENT_MESSAGE_TYPE_CLIENT_ASSERT &&
1954 message_type != NETAGENT_MESSAGE_TYPE_CLIENT_UNASSERT &&
1955 message_type != NETAGENT_MESSAGE_TYPE_REQUEST_NEXUS &&
1956 message_type != NETAGENT_MESSAGE_TYPE_CLOSE_NEXUS &&
1957 message_type != NETAGENT_MESSAGE_TYPE_ABORT_NEXUS) {
39037602 1958 NETAGENTLOG(LOG_ERR, "Client netagent message type (%d) is invalid", message_type);
0a7de745 1959 return EINVAL;
39037602
A
1960 }
1961
1962 lck_rw_lock_shared(&netagent_lock);
1963 bool should_unlock = TRUE;
1964 struct netagent_wrapper *wrapper = netagent_find_agent_with_uuid(agent_uuid);
1965 if (wrapper == NULL) {
5ba3f43e 1966 NETAGENTLOG0(LOG_DEBUG, "Requested netagent for nexus instance could not be found");
39037602
A
1967 error = ENOENT;
1968 goto done;
1969 }
1970
1971 if (message_type == NETAGENT_MESSAGE_TYPE_CLIENT_TRIGGER) {
1972 if ((wrapper->netagent.netagent_flags & NETAGENT_FLAG_USER_ACTIVATED) == 0) {
1973 // Agent does not accept user triggers
1974 // Don't log, since this is a common case used to trigger events that cellular data is blocked, etc.
1975 error = ENOTSUP;
1976
5ba3f43e
A
1977
1978 pid_t report_pid = 0;
1979 uuid_t report_proc_uuid = {};
1980 if (parameters != NULL) {
cb323159
A
1981 report_pid = parameters->u.nexus_request.epid;
1982 uuid_copy(report_proc_uuid, parameters->u.nexus_request.euuid);
5ba3f43e
A
1983 } else {
1984 struct proc *p = current_proc();
1985 if (p != NULL) {
1986 report_pid = proc_pid(p);
1987 proc_getexecutableuuid(p, report_proc_uuid, sizeof(report_proc_uuid));
1988 }
39037602 1989 }
5ba3f43e 1990 netagent_send_cellular_failed_event(wrapper, report_pid, report_proc_uuid);
39037602
A
1991 goto done;
1992 }
1993 } else if (message_type == NETAGENT_MESSAGE_TYPE_REQUEST_NEXUS ||
0a7de745
A
1994 message_type == NETAGENT_MESSAGE_TYPE_CLOSE_NEXUS ||
1995 message_type == NETAGENT_MESSAGE_TYPE_ABORT_NEXUS) {
cb323159
A
1996 bool is_nexus_agent = ((wrapper->netagent.netagent_flags &
1997 (NETAGENT_FLAG_NEXUS_PROVIDER |
1998 NETAGENT_FLAG_NEXUS_LISTENER |
1999 NETAGENT_FLAG_CUSTOM_IP_NEXUS |
2000 NETAGENT_FLAG_CUSTOM_ETHER_NEXUS |
2001 NETAGENT_FLAG_INTERPOSE_NEXUS)) != 0);
2002 if (!is_nexus_agent) {
39037602
A
2003 NETAGENTLOG0(LOG_ERR, "Requested netagent for nexus instance is not a nexus provider");
2004 // Agent is not a nexus provider
2005 error = EINVAL;
2006 goto done;
2007 }
2008
2009 if ((wrapper->netagent.netagent_flags & NETAGENT_FLAG_ACTIVE) == 0) {
2010 // Agent not active
2011 NETAGENTLOG0(LOG_INFO, "Requested netagent for nexus instance is not active");
2012 error = EINVAL;
2013 goto done;
2014 }
2015 }
2016
5ba3f43e 2017 if (wrapper->control_unit == 0) {
5ba3f43e
A
2018 if (wrapper->event_handler == NULL) {
2019 // No event handler registered for kernel agent
2020 error = EINVAL;
2021 } else {
d9a64523
A
2022 // We hold the shared lock during the event handler callout, so it is expected
2023 // that the event handler will not lead to any registrations or unregistrations
2024 // of network agents.
2025 error = wrapper->event_handler(message_type, necp_client_uuid, pid, handle,
0a7de745
A
2026 wrapper->event_context, parameters,
2027 assigned_results, assigned_results_length);
5ba3f43e
A
2028 if (error != 0) {
2029 VERIFY(assigned_results == NULL || *assigned_results == NULL);
2030 VERIFY(assigned_results_length == NULL || *assigned_results_length == 0);
2031 }
2032 }
2033 } else {
2034 // ABORT_NEXUS is kernel-private, so translate it for userspace nexus
2035 if (message_type == NETAGENT_MESSAGE_TYPE_ABORT_NEXUS) {
2036 message_type = NETAGENT_MESSAGE_TYPE_CLOSE_NEXUS;
2037 }
2038
2039 error = netagent_send_client_message(wrapper, necp_client_uuid, message_type);
2040 if (error == 0 && message_type == NETAGENT_MESSAGE_TYPE_CLIENT_TRIGGER) {
2041 if (lck_rw_lock_shared_to_exclusive(&netagent_lock)) {
2042 // Grab the lock exclusively to add a pending client to the list
2043 struct netagent_client *new_pending_client = NULL;
2044 MALLOC(new_pending_client, struct netagent_client *, sizeof(*new_pending_client), M_NETAGENT, M_WAITOK);
2045 if (new_pending_client == NULL) {
2046 NETAGENTLOG0(LOG_ERR, "Failed to allocate client for trigger");
2047 } else {
2048 uuid_copy(new_pending_client->client_id, necp_client_uuid);
2049 if (parameters != NULL) {
cb323159
A
2050 new_pending_client->client_pid = parameters->u.nexus_request.epid;
2051 uuid_copy(new_pending_client->client_proc_uuid, parameters->u.nexus_request.euuid);
5ba3f43e
A
2052 } else {
2053 struct proc *p = current_proc();
2054 if (p != NULL) {
2055 new_pending_client->client_pid = proc_pid(p);
2056 proc_getexecutableuuid(p, new_pending_client->client_proc_uuid, sizeof(new_pending_client->client_proc_uuid));
2057 }
2058 }
2059 LIST_INSERT_HEAD(&wrapper->pending_triggers_list, new_pending_client, client_chain);
39037602 2060 }
5ba3f43e
A
2061 } else {
2062 // If lck_rw_lock_shared_to_exclusive fails, it unlocks automatically
2063 should_unlock = FALSE;
39037602 2064 }
39037602
A
2065 }
2066 }
5ba3f43e 2067 NETAGENTLOG(((error && error != ENOENT) ? LOG_ERR : LOG_INFO), "Send message %d for client (error %d)", message_type, error);
a39ff7e2
A
2068 if (message_type == NETAGENT_MESSAGE_TYPE_CLIENT_TRIGGER) {
2069 uuid_string_t uuid_str;
2070 uuid_unparse(agent_uuid, uuid_str);
2071 NETAGENTLOG(LOG_NOTICE, "Triggered network agent %s, error = %d", uuid_str, error);
2072 }
39037602
A
2073done:
2074 if (should_unlock) {
2075 lck_rw_done(&netagent_lock);
2076 }
0a7de745 2077 return error;
39037602
A
2078}
2079
5ba3f43e 2080int
d9a64523 2081netagent_client_message(uuid_t agent_uuid, uuid_t necp_client_uuid, pid_t pid, void *handle, u_int8_t message_type)
5ba3f43e 2082{
0a7de745 2083 return netagent_client_message_with_params(agent_uuid, necp_client_uuid, pid, handle, message_type, NULL, NULL, NULL);
5ba3f43e
A
2084}
2085
813fb2f6
A
2086int
2087netagent_use(uuid_t agent_uuid, uint64_t *out_use_count)
2088{
2089 int error = 0;
2090
2091 lck_rw_lock_exclusive(&netagent_lock);
2092 struct netagent_wrapper *wrapper = netagent_find_agent_with_uuid(agent_uuid);
2093 if (wrapper == NULL) {
2094 NETAGENTLOG0(LOG_ERR, "netagent_assert: Requested netagent UUID is not registered");
2095 error = ENOENT;
2096 goto done;
2097 }
2098
2099 uint64_t current_count = wrapper->use_count;
2100 wrapper->use_count++;
2101
2102 if (out_use_count != NULL) {
2103 *out_use_count = current_count;
2104 }
2105
2106done:
2107 lck_rw_done(&netagent_lock);
0a7de745 2108 return error;
813fb2f6
A
2109}
2110
39037602
A
2111int
2112netagent_copyout(uuid_t agent_uuid, user_addr_t user_addr, u_int32_t user_size)
2113{
2114 int error = 0;
2115
2116 lck_rw_lock_shared(&netagent_lock);
2117 struct netagent_wrapper *wrapper = netagent_find_agent_with_uuid(agent_uuid);
2118 if (wrapper == NULL) {
5ba3f43e 2119 NETAGENTLOG0(LOG_DEBUG, "Requested netagent for nexus instance could not be found");
39037602
A
2120 error = ENOENT;
2121 goto done;
2122 }
2123
2124 u_int32_t total_size = (sizeof(struct netagent) + wrapper->netagent.netagent_data_size);
2125 if (user_size < total_size) {
2126 NETAGENTLOG(LOG_ERR, "Provided user buffer is too small (%u < %u)", user_size, total_size);
2127 error = EINVAL;
2128 goto done;
2129 }
2130
2131 error = copyout(&wrapper->netagent, user_addr, total_size);
2132
2133 NETAGENTLOG((error ? LOG_ERR : LOG_DEBUG), "Copied agent content (error %d)", error);
2134done:
2135 lck_rw_done(&netagent_lock);
0a7de745 2136 return error;
39037602
A
2137}
2138
3e170ce0
A
2139int
2140netagent_trigger(struct proc *p, struct netagent_trigger_args *uap, int32_t *retval)
2141{
2142#pragma unused(p, retval)
2143 uuid_t agent_uuid;
2144 int error = 0;
2145
2146 if (uap == NULL) {
2147 NETAGENTLOG0(LOG_ERR, "uap == NULL");
0a7de745 2148 return EINVAL;
3e170ce0
A
2149 }
2150
2151 if (uap->agent_uuid) {
2152 if (uap->agent_uuidlen != sizeof(uuid_t)) {
cb323159
A
2153 NETAGENTLOG(LOG_ERR, "Incorrect length (got %zu, expected %lu)",
2154 (size_t)uap->agent_uuidlen, sizeof(uuid_t));
0a7de745 2155 return ERANGE;
3e170ce0
A
2156 }
2157
2158 error = copyin(uap->agent_uuid, agent_uuid, sizeof(uuid_t));
2159 if (error) {
2160 NETAGENTLOG(LOG_ERR, "copyin error (%d)", error);
0a7de745 2161 return error;
3e170ce0
A
2162 }
2163 }
2164
2165 if (uuid_is_null(agent_uuid)) {
2166 NETAGENTLOG0(LOG_ERR, "Requested netagent UUID is empty");
0a7de745 2167 return EINVAL;
3e170ce0
A
2168 }
2169
2170 lck_rw_lock_shared(&netagent_lock);
2171 struct netagent_wrapper *wrapper = netagent_find_agent_with_uuid(agent_uuid);
2172 if (wrapper == NULL) {
2173 NETAGENTLOG0(LOG_ERR, "Requested netagent UUID is not registered");
2174 error = ENOENT;
2175 goto done;
2176 }
2177
2178 if ((wrapper->netagent.netagent_flags & NETAGENT_FLAG_USER_ACTIVATED) == 0) {
2179 // Agent does not accept triggers
2180 NETAGENTLOG0(LOG_ERR, "Requested netagent UUID is not eligible for triggering");
39037602 2181 error = ENOTSUP;
3e170ce0
A
2182 goto done;
2183 }
2184
2185 if ((wrapper->netagent.netagent_flags & NETAGENT_FLAG_ACTIVE)) {
2186 // Agent already active
2187 NETAGENTLOG0(LOG_INFO, "Requested netagent UUID is already active");
2188 error = 0;
2189 goto done;
2190 }
2191
2192 error = netagent_send_trigger(wrapper, p, NETAGENT_TRIGGER_FLAG_USER, NETAGENT_MESSAGE_TYPE_TRIGGER);
2193 NETAGENTLOG((error ? LOG_ERR : LOG_INFO), "Triggered netagent (error %d)", error);
2194done:
2195 lck_rw_done(&netagent_lock);
0a7de745 2196 return error;
3e170ce0 2197}