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