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