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