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