2 * Copyright (c) 2014 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
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>
39 #include <sys/kpi_mbuf.h>
40 #include <sys/sysctl.h>
42 #include <sys/kern_event.h>
43 #include <sys/sysproto.h>
44 #include <net/network_agent.h>
45 #include <net/if_var.h>
47 u_int32_t netagent_debug
= LOG_NOTICE
; // 0=None, 1=Basic
49 SYSCTL_NODE(_net
, OID_AUTO
, netagent
, CTLFLAG_RW
| CTLFLAG_LOCKED
, 0, "NetworkAgent");
50 SYSCTL_INT(_net_netagent
, OID_AUTO
, debug
, CTLFLAG_LOCKED
| CTLFLAG_RW
, &netagent_debug
, 0, "");
52 static int netagent_registered_count
= 0;
53 SYSCTL_INT(_net_netagent
, OID_AUTO
, registered_count
, CTLFLAG_RD
| CTLFLAG_LOCKED
,
54 &netagent_registered_count
, 0, "");
56 static int netagent_active_count
= 0;
57 SYSCTL_INT(_net_netagent
, OID_AUTO
, active_count
, CTLFLAG_RD
| CTLFLAG_LOCKED
,
58 &netagent_active_count
, 0, "");
60 #define NETAGENTLOG(level, format, ...) do { \
61 if (level <= netagent_debug) \
62 log((level > LOG_NOTICE ? LOG_NOTICE : level), "%s: " format "\n", __FUNCTION__, __VA_ARGS__); \
65 #define NETAGENTLOG0(level, msg) do { \
66 if (level <= netagent_debug) \
67 log((level > LOG_NOTICE ? LOG_NOTICE : level), "%s: %s\n", __FUNCTION__, msg); \
70 struct netagent_assertion
{
71 LIST_ENTRY(netagent_assertion
) assertion_chain
;
75 struct netagent_wrapper
{
76 LIST_ENTRY(netagent_wrapper
) master_chain
;
77 u_int32_t control_unit
;
78 struct netagent netagent
;
81 struct netagent_session
{
82 u_int32_t control_unit
;
83 struct netagent_wrapper
*wrapper
;
84 LIST_HEAD(_netagent_assertion_list
, netagent_assertion
) assertion_list
;
87 static LIST_HEAD(_netagent_list
, netagent_wrapper
) master_netagent_list
;
89 static kern_ctl_ref netagent_kctlref
;
90 static u_int32_t netagent_family
;
91 static OSMallocTag netagent_malloc_tag
;
92 static lck_grp_attr_t
*netagent_grp_attr
= NULL
;
93 static lck_attr_t
*netagent_mtx_attr
= NULL
;
94 static lck_grp_t
*netagent_mtx_grp
= NULL
;
95 decl_lck_rw_data(static, netagent_lock
);
97 static errno_t
netagent_register_control(void);
98 static errno_t
netagent_ctl_connect(kern_ctl_ref kctlref
, struct sockaddr_ctl
*sac
,
100 static errno_t
netagent_ctl_disconnect(kern_ctl_ref kctlref
, u_int32_t unit
, void *unitinfo
);
101 static errno_t
netagent_ctl_send(kern_ctl_ref kctlref
, u_int32_t unit
, void *unitinfo
,
102 mbuf_t m
, int flags
);
103 static void netagent_ctl_rcvd(kern_ctl_ref kctlref
, u_int32_t unit
, void *unitinfo
, int flags
);
104 static errno_t
netagent_ctl_getopt(kern_ctl_ref kctlref
, u_int32_t unit
, void *unitinfo
,
105 int opt
, void *data
, size_t *len
);
106 static errno_t
netagent_ctl_setopt(kern_ctl_ref kctlref
, u_int32_t unit
, void *unitinfo
,
107 int opt
, void *data
, size_t len
);
109 static int netagent_send_ctl_data(u_int32_t control_unit
, u_int8_t
*buffer
, size_t buffer_size
);
111 static struct netagent_session
*netagent_create_session(u_int32_t control_unit
);
112 static void netagent_delete_session(struct netagent_session
*session
);
114 static void netagent_handle_register(struct netagent_session
*session
, u_int32_t message_id
,
115 u_int32_t payload_length
, mbuf_t packet
, int offset
);
116 static void netagent_handle_unregister(struct netagent_session
*session
, u_int32_t message_id
,
117 u_int32_t payload_length
, mbuf_t packet
, int offset
);
118 static void netagent_handle_update(struct netagent_session
*session
, u_int32_t message_id
,
119 u_int32_t payload_length
, mbuf_t packet
, int offset
);
120 static void netagent_handle_get(struct netagent_session
*session
, u_int32_t message_id
,
121 u_int32_t payload_length
, mbuf_t packet
, int offset
);
122 static void netagent_handle_assert(struct netagent_session
*session
, u_int32_t message_id
,
123 u_int32_t payload_length
, mbuf_t packet
, int offset
);
124 static void netagent_handle_unassert(struct netagent_session
*session
, u_int32_t message_id
,
125 u_int32_t payload_length
, mbuf_t packet
, int offset
);
127 static struct netagent_wrapper
*netagent_find_agent_with_uuid(uuid_t uuid
);
134 result
= netagent_register_control();
139 netagent_grp_attr
= lck_grp_attr_alloc_init();
140 if (netagent_grp_attr
== NULL
) {
141 NETAGENTLOG0(LOG_ERR
, "lck_grp_attr_alloc_init failed");
146 netagent_mtx_grp
= lck_grp_alloc_init(NETAGENT_CONTROL_NAME
, netagent_grp_attr
);
147 if (netagent_mtx_grp
== NULL
) {
148 NETAGENTLOG0(LOG_ERR
, "lck_grp_alloc_init failed");
153 netagent_mtx_attr
= lck_attr_alloc_init();
154 if (netagent_mtx_attr
== NULL
) {
155 NETAGENTLOG0(LOG_ERR
, "lck_attr_alloc_init failed");
160 lck_rw_init(&netagent_lock
, netagent_mtx_grp
, netagent_mtx_attr
);
162 LIST_INIT(&master_netagent_list
);
166 if (netagent_mtx_attr
!= NULL
) {
167 lck_attr_free(netagent_mtx_attr
);
168 netagent_mtx_attr
= NULL
;
170 if (netagent_mtx_grp
!= NULL
) {
171 lck_grp_free(netagent_mtx_grp
);
172 netagent_mtx_grp
= NULL
;
174 if (netagent_grp_attr
!= NULL
) {
175 lck_grp_attr_free(netagent_grp_attr
);
176 netagent_grp_attr
= NULL
;
178 if (netagent_kctlref
!= NULL
) {
179 ctl_deregister(netagent_kctlref
);
180 netagent_kctlref
= NULL
;
187 netagent_register_control(void)
189 struct kern_ctl_reg kern_ctl
;
192 // Create a tag to allocate memory
193 netagent_malloc_tag
= OSMalloc_Tagalloc(NETAGENT_CONTROL_NAME
, OSMT_DEFAULT
);
195 // Find a unique value for our interface family
196 result
= mbuf_tag_id_find(NETAGENT_CONTROL_NAME
, &netagent_family
);
198 NETAGENTLOG(LOG_ERR
, "mbuf_tag_id_find_internal failed: %d", result
);
202 bzero(&kern_ctl
, sizeof(kern_ctl
));
203 strlcpy(kern_ctl
.ctl_name
, NETAGENT_CONTROL_NAME
, sizeof(kern_ctl
.ctl_name
));
204 kern_ctl
.ctl_name
[sizeof(kern_ctl
.ctl_name
) - 1] = 0;
205 kern_ctl
.ctl_flags
= CTL_FLAG_PRIVILEGED
; // Require root
206 kern_ctl
.ctl_sendsize
= 64 * 1024;
207 kern_ctl
.ctl_recvsize
= 64 * 1024;
208 kern_ctl
.ctl_connect
= netagent_ctl_connect
;
209 kern_ctl
.ctl_disconnect
= netagent_ctl_disconnect
;
210 kern_ctl
.ctl_send
= netagent_ctl_send
;
211 kern_ctl
.ctl_rcvd
= netagent_ctl_rcvd
;
212 kern_ctl
.ctl_setopt
= netagent_ctl_setopt
;
213 kern_ctl
.ctl_getopt
= netagent_ctl_getopt
;
215 result
= ctl_register(&kern_ctl
, &netagent_kctlref
);
217 NETAGENTLOG(LOG_ERR
, "ctl_register failed: %d", result
);
225 netagent_ctl_connect(kern_ctl_ref kctlref
, struct sockaddr_ctl
*sac
, void **unitinfo
)
227 #pragma unused(kctlref)
228 *unitinfo
= netagent_create_session(sac
->sc_unit
);
229 if (*unitinfo
== NULL
) {
230 // Could not allocate session
238 netagent_ctl_disconnect(kern_ctl_ref kctlref
, u_int32_t unit
, void *unitinfo
)
240 #pragma unused(kctlref, unit)
241 struct netagent_session
*session
= (struct netagent_session
*)unitinfo
;
242 if (session
!= NULL
) {
243 netagent_delete_session(session
);
251 netagent_post_event(uuid_t agent_uuid
, u_int32_t event_code
)
253 struct kev_msg ev_msg
;
254 memset(&ev_msg
, 0, sizeof(ev_msg
));
256 struct kev_netagent_data event_data
;
258 ev_msg
.vendor_code
= KEV_VENDOR_APPLE
;
259 ev_msg
.kev_class
= KEV_NETWORK_CLASS
;
260 ev_msg
.kev_subclass
= KEV_NETAGENT_SUBCLASS
;
261 ev_msg
.event_code
= event_code
;
263 uuid_copy(event_data
.netagent_uuid
, agent_uuid
);
264 ev_msg
.dv
[0].data_ptr
= &event_data
;
265 ev_msg
.dv
[0].data_length
= sizeof(event_data
);
267 kev_post_msg(&ev_msg
);
272 netagent_buffer_write_message_header(u_int8_t
*buffer
, u_int8_t message_type
, u_int8_t flags
,
273 u_int32_t message_id
, u_int32_t error
, u_int32_t payload_length
)
275 ((struct netagent_message_header
*)(void *)buffer
)->message_type
= message_type
;
276 ((struct netagent_message_header
*)(void *)buffer
)->message_flags
= flags
;
277 ((struct netagent_message_header
*)(void *)buffer
)->message_id
= message_id
;
278 ((struct netagent_message_header
*)(void *)buffer
)->message_error
= error
;
279 ((struct netagent_message_header
*)(void *)buffer
)->message_payload_length
= payload_length
;
280 return (buffer
+ sizeof(struct netagent_message_header
));
284 netagent_send_ctl_data(u_int32_t control_unit
, u_int8_t
*buffer
, size_t buffer_size
)
286 if (netagent_kctlref
== NULL
|| control_unit
== 0 || buffer
== NULL
|| buffer_size
== 0) {
290 return ctl_enqueuedata(netagent_kctlref
, control_unit
, buffer
, buffer_size
, CTL_DATA_EOR
);
294 netagent_send_trigger(struct netagent_wrapper
*wrapper
, struct proc
*p
, u_int32_t flags
, u_int32_t trigger_type
)
297 struct netagent_trigger_message
*trigger_message
= NULL
;
298 u_int8_t
*trigger
= NULL
;
299 size_t trigger_size
= sizeof(struct netagent_message_header
) + sizeof(struct netagent_trigger_message
);
301 MALLOC(trigger
, u_int8_t
*, trigger_size
, M_NETAGENT
, M_WAITOK
);
302 if (trigger
== NULL
) {
306 (void)netagent_buffer_write_message_header(trigger
, trigger_type
, 0, 0, 0, sizeof(struct netagent_trigger_message
));
308 trigger_message
= (struct netagent_trigger_message
*)(void *)(trigger
+ sizeof(struct netagent_message_header
));
309 trigger_message
->trigger_flags
= flags
;
311 trigger_message
->trigger_pid
= proc_pid(p
);
312 proc_getexecutableuuid(p
, trigger_message
->trigger_proc_uuid
, sizeof(trigger_message
->trigger_proc_uuid
));
314 trigger_message
->trigger_pid
= 0;
315 uuid_clear(trigger_message
->trigger_proc_uuid
);
318 if ((error
= netagent_send_ctl_data(wrapper
->control_unit
, (u_int8_t
*)trigger
, trigger_size
))) {
319 NETAGENTLOG(LOG_ERR
, "Failed to send trigger message on control unit %d", wrapper
->control_unit
);
322 FREE(trigger
, M_NETAGENT
);
327 netagent_send_success_response(struct netagent_session
*session
, u_int8_t message_type
, u_int32_t message_id
)
330 u_int8_t
*response
= NULL
;
331 size_t response_size
= sizeof(struct netagent_message_header
);
332 MALLOC(response
, u_int8_t
*, response_size
, M_NETAGENT
, M_WAITOK
);
333 if (response
== NULL
) {
336 (void)netagent_buffer_write_message_header(response
, message_type
, NETAGENT_MESSAGE_FLAGS_RESPONSE
, message_id
, 0, 0);
338 if ((error
= netagent_send_ctl_data(session
->control_unit
, (u_int8_t
*)response
, response_size
))) {
339 NETAGENTLOG0(LOG_ERR
, "Failed to send response");
342 FREE(response
, M_NETAGENT
);
347 netagent_send_error_response(struct netagent_session
*session
, u_int8_t message_type
,
348 u_int32_t message_id
, u_int32_t error_code
)
351 u_int8_t
*response
= NULL
;
352 size_t response_size
= sizeof(struct netagent_message_header
);
353 MALLOC(response
, u_int8_t
*, response_size
, M_NETAGENT
, M_WAITOK
);
354 if (response
== NULL
) {
357 (void)netagent_buffer_write_message_header(response
, message_type
, NETAGENT_MESSAGE_FLAGS_RESPONSE
,
358 message_id
, error_code
, 0);
360 if ((error
= netagent_send_ctl_data(session
->control_unit
, (u_int8_t
*)response
, response_size
))) {
361 NETAGENTLOG0(LOG_ERR
, "Failed to send response");
364 FREE(response
, M_NETAGENT
);
369 netagent_ctl_send(kern_ctl_ref kctlref
, u_int32_t unit
, void *unitinfo
, mbuf_t packet
, int flags
)
371 #pragma unused(kctlref, unit, flags)
372 struct netagent_session
*session
= (struct netagent_session
*)unitinfo
;
373 struct netagent_message_header header
;
376 if (session
== NULL
) {
377 NETAGENTLOG0(LOG_ERR
, "Got a NULL session");
382 if (mbuf_pkthdr_len(packet
) < sizeof(header
)) {
383 NETAGENTLOG(LOG_ERR
, "Got a bad packet, length (%lu) < sizeof header (%lu)",
384 mbuf_pkthdr_len(packet
), sizeof(header
));
389 error
= mbuf_copydata(packet
, 0, sizeof(header
), &header
);
391 NETAGENTLOG(LOG_ERR
, "mbuf_copydata failed for the header: %d", error
);
396 switch (header
.message_type
) {
397 case NETAGENT_MESSAGE_TYPE_REGISTER
: {
398 netagent_handle_register(session
, header
.message_id
, header
.message_payload_length
,
399 packet
, sizeof(header
));
402 case NETAGENT_MESSAGE_TYPE_UNREGISTER
: {
403 netagent_handle_unregister(session
, header
.message_id
, header
.message_payload_length
,
404 packet
, sizeof(header
));
407 case NETAGENT_MESSAGE_TYPE_UPDATE
: {
408 netagent_handle_update(session
, header
.message_id
, header
.message_payload_length
,
409 packet
, sizeof(header
));
412 case NETAGENT_MESSAGE_TYPE_GET
: {
413 netagent_handle_get(session
, header
.message_id
, header
.message_payload_length
,
414 packet
, sizeof(header
));
417 case NETAGENT_MESSAGE_TYPE_ASSERT
: {
418 netagent_handle_assert(session
, header
.message_id
, header
.message_payload_length
,
419 packet
, sizeof(header
));
422 case NETAGENT_MESSAGE_TYPE_UNASSERT
: {
423 netagent_handle_unassert(session
, header
.message_id
, header
.message_payload_length
,
424 packet
, sizeof(header
));
428 NETAGENTLOG(LOG_ERR
, "Received unknown message type %d", header
.message_type
);
429 netagent_send_error_response(session
, header
.message_type
, header
.message_id
,
430 NETAGENT_MESSAGE_ERROR_UNKNOWN_TYPE
);
441 netagent_ctl_rcvd(kern_ctl_ref kctlref
, u_int32_t unit
, void *unitinfo
, int flags
)
443 #pragma unused(kctlref, unit, unitinfo, flags)
448 netagent_ctl_getopt(kern_ctl_ref kctlref
, u_int32_t unit
, void *unitinfo
, int opt
,
449 void *data
, size_t *len
)
451 #pragma unused(kctlref, unit, unitinfo, opt, data, len)
456 netagent_ctl_setopt(kern_ctl_ref kctlref
, u_int32_t unit
, void *unitinfo
, int opt
,
457 void *data
, size_t len
)
459 #pragma unused(kctlref, unit, unitinfo, opt, data, len)
463 // Session Management
464 static struct netagent_session
*
465 netagent_create_session(u_int32_t control_unit
)
467 struct netagent_session
*new_session
= NULL
;
469 MALLOC(new_session
, struct netagent_session
*, sizeof(*new_session
), M_NETAGENT
, M_WAITOK
);
470 if (new_session
== NULL
) {
473 NETAGENTLOG(LOG_DEBUG
, "Create agent session, control unit %d", control_unit
);
474 memset(new_session
, 0, sizeof(*new_session
));
475 new_session
->control_unit
= control_unit
;
476 LIST_INIT(&new_session
->assertion_list
);
477 new_session
->wrapper
= NULL
;
479 return (new_session
);
483 netagent_unregister_session_wrapper(struct netagent_session
*session
)
485 bool unregistered
= FALSE
;
486 uuid_t unregistered_uuid
;
487 struct netagent_wrapper
*wrapper
= NULL
;
488 lck_rw_lock_exclusive(&netagent_lock
);
489 if (session
!= NULL
) {
490 wrapper
= session
->wrapper
;
491 if (wrapper
!= NULL
) {
492 if (netagent_registered_count
> 0) {
493 netagent_registered_count
--;
495 if ((session
->wrapper
->netagent
.netagent_flags
& NETAGENT_FLAG_ACTIVE
) &&
496 netagent_active_count
> 0) {
497 netagent_active_count
--;
500 LIST_REMOVE(wrapper
, master_chain
);
503 uuid_copy(unregistered_uuid
, session
->wrapper
->netagent
.netagent_uuid
);
505 FREE(wrapper
, M_NETAGENT
);
506 session
->wrapper
= NULL
;
507 NETAGENTLOG0(LOG_DEBUG
, "Unregistered agent");
510 lck_rw_done(&netagent_lock
);
513 netagent_post_event(unregistered_uuid
, KEV_NETAGENT_UNREGISTERED
);
514 ifnet_clear_netagent(unregistered_uuid
);
519 netagent_delete_session(struct netagent_session
*session
)
521 if (session
!= NULL
) {
522 netagent_unregister_session_wrapper(session
);
524 // Unassert any pending assertions
525 lck_rw_lock_shared(&netagent_lock
);
526 struct netagent_assertion
*search_assertion
= NULL
;
527 struct netagent_assertion
*temp_assertion
= NULL
;
528 LIST_FOREACH_SAFE(search_assertion
, &session
->assertion_list
, assertion_chain
, temp_assertion
) {
529 struct netagent_wrapper
*wrapper
= netagent_find_agent_with_uuid(search_assertion
->asserted_uuid
);
530 if (wrapper
!= NULL
) {
531 netagent_send_trigger(wrapper
, current_proc(), NETAGENT_TRIGGER_FLAG_USER
, NETAGENT_MESSAGE_TYPE_TRIGGER_UNASSERT
);
533 LIST_REMOVE(search_assertion
, assertion_chain
);
534 FREE(search_assertion
, M_NETAGENT
);
536 lck_rw_done(&netagent_lock
);
538 FREE(session
, M_NETAGENT
);
543 netagent_packet_get_netagent_data_size(mbuf_t packet
, int offset
, int *err
)
547 struct netagent netagent_peek
;
548 memset(&netagent_peek
, 0, sizeof(netagent_peek
));
552 error
= mbuf_copydata(packet
, offset
, sizeof(netagent_peek
), &netagent_peek
);
558 return (netagent_peek
.netagent_data_size
);
562 netagent_handle_register(struct netagent_session
*session
, u_int32_t message_id
,
563 u_int32_t payload_length
, mbuf_t packet
, int offset
)
567 struct netagent_wrapper
*new_wrapper
= NULL
;
568 u_int32_t response_error
= NETAGENT_MESSAGE_ERROR_INTERNAL
;
569 uuid_t netagent_uuid
;
570 uuid_clear(netagent_uuid
);
572 if (session
== NULL
) {
573 NETAGENTLOG0(LOG_ERR
, "Failed to find session");
574 response_error
= NETAGENT_MESSAGE_ERROR_INTERNAL
;
578 if (session
->wrapper
!= NULL
) {
579 NETAGENTLOG0(LOG_ERR
, "Session already has a registered agent");
580 response_error
= NETAGENT_MESSAGE_ERROR_ALREADY_REGISTERED
;
584 if (payload_length
< sizeof(struct netagent
)) {
585 NETAGENTLOG(LOG_ERR
, "Register message size too small for agent: (%d < %d)",
586 payload_length
, sizeof(struct netagent
));
587 response_error
= NETAGENT_MESSAGE_ERROR_INVALID_DATA
;
591 data_size
= netagent_packet_get_netagent_data_size(packet
, offset
, &error
);
592 if (error
|| data_size
< 0 || data_size
> NETAGENT_MAX_DATA_SIZE
) {
593 NETAGENTLOG(LOG_ERR
, "Register message size could not be read, error %d data_size %d",
595 response_error
= NETAGENT_MESSAGE_ERROR_INVALID_DATA
;
599 MALLOC(new_wrapper
, struct netagent_wrapper
*, sizeof(*new_wrapper
) + data_size
, M_NETAGENT
, M_WAITOK
);
600 if (new_wrapper
== NULL
) {
601 NETAGENTLOG0(LOG_ERR
, "Failed to allocate agent");
602 response_error
= NETAGENT_MESSAGE_ERROR_INTERNAL
;
606 memset(new_wrapper
, 0, sizeof(*new_wrapper
) + data_size
);
608 error
= mbuf_copydata(packet
, offset
, sizeof(struct netagent
) + data_size
,
609 &new_wrapper
->netagent
);
611 NETAGENTLOG(LOG_ERR
, "Failed to read data into agent structure: %d", error
);
612 FREE(new_wrapper
, M_NETAGENT
);
613 response_error
= NETAGENT_MESSAGE_ERROR_INTERNAL
;
617 lck_rw_lock_exclusive(&netagent_lock
);
619 new_wrapper
->control_unit
= session
->control_unit
;
621 session
->wrapper
= new_wrapper
;
622 LIST_INSERT_HEAD(&master_netagent_list
, new_wrapper
, master_chain
);
624 new_wrapper
->netagent
.netagent_flags
|= NETAGENT_FLAG_REGISTERED
;
625 netagent_registered_count
++;
626 if (new_wrapper
->netagent
.netagent_flags
& NETAGENT_FLAG_ACTIVE
) {
627 netagent_active_count
++;
630 lck_rw_done(&netagent_lock
);
632 NETAGENTLOG0(LOG_DEBUG
, "Registered new agent");
633 netagent_send_success_response(session
, NETAGENT_MESSAGE_TYPE_REGISTER
, message_id
);
634 netagent_post_event(new_wrapper
->netagent
.netagent_uuid
, KEV_NETAGENT_REGISTERED
);
637 netagent_send_error_response(session
, NETAGENT_MESSAGE_TYPE_REGISTER
, message_id
, response_error
);
641 netagent_handle_unregister(struct netagent_session
*session
, u_int32_t message_id
,
642 u_int32_t payload_length
, mbuf_t packet
, int offset
)
644 #pragma unused(payload_length, packet, offset)
645 u_int32_t response_error
= NETAGENT_MESSAGE_ERROR_INTERNAL
;
647 if (session
== NULL
) {
648 NETAGENTLOG0(LOG_ERR
, "Failed to find session");
649 response_error
= NETAGENT_MESSAGE_ERROR_INTERNAL
;
653 netagent_unregister_session_wrapper(session
);
655 netagent_send_success_response(session
, NETAGENT_MESSAGE_TYPE_UNREGISTER
, message_id
);
658 netagent_send_error_response(session
, NETAGENT_MESSAGE_TYPE_UNREGISTER
, message_id
, response_error
);
662 netagent_handle_update(struct netagent_session
*session
, u_int32_t message_id
,
663 u_int32_t payload_length
, mbuf_t packet
, int offset
)
667 struct netagent_wrapper
*new_wrapper
= NULL
;
668 u_int32_t response_error
= NETAGENT_MESSAGE_ERROR_INTERNAL
;
669 uuid_t netagent_uuid
;
670 uuid_clear(netagent_uuid
);
672 if (session
== NULL
) {
673 NETAGENTLOG0(LOG_ERR
, "Failed to find session");
674 response_error
= NETAGENT_MESSAGE_ERROR_INTERNAL
;
678 if (session
->wrapper
== NULL
) {
679 NETAGENTLOG0(LOG_ERR
, "Session has no agent to update");
680 response_error
= NETAGENT_MESSAGE_ERROR_NOT_REGISTERED
;
684 if (payload_length
< sizeof(struct netagent
)) {
685 NETAGENTLOG(LOG_ERR
, "Update message size too small for agent: (%d < %d)",
686 payload_length
, sizeof(struct netagent
));
687 response_error
= NETAGENT_MESSAGE_ERROR_INVALID_DATA
;
691 data_size
= netagent_packet_get_netagent_data_size(packet
, offset
, &error
);
692 if (error
|| data_size
< 0 || data_size
> NETAGENT_MAX_DATA_SIZE
) {
693 NETAGENTLOG(LOG_ERR
, "Update message size could not be read, error %d data_size %d",
695 response_error
= NETAGENT_MESSAGE_ERROR_INVALID_DATA
;
699 MALLOC(new_wrapper
, struct netagent_wrapper
*, sizeof(*new_wrapper
) + data_size
, M_NETAGENT
, M_WAITOK
);
700 if (new_wrapper
== NULL
) {
701 NETAGENTLOG0(LOG_ERR
, "Failed to allocate agent");
702 response_error
= NETAGENT_MESSAGE_ERROR_INTERNAL
;
706 memset(new_wrapper
, 0, sizeof(*new_wrapper
) + data_size
);
708 error
= mbuf_copydata(packet
, offset
, sizeof(struct netagent
) + data_size
, &new_wrapper
->netagent
);
710 NETAGENTLOG(LOG_ERR
, "Failed to read data into agent structure: %d", error
);
711 FREE(new_wrapper
, M_NETAGENT
);
712 response_error
= NETAGENT_MESSAGE_ERROR_INTERNAL
;
716 lck_rw_lock_exclusive(&netagent_lock
);
718 if (uuid_compare(session
->wrapper
->netagent
.netagent_uuid
, new_wrapper
->netagent
.netagent_uuid
) != 0 ||
719 memcmp(&session
->wrapper
->netagent
.netagent_domain
, &new_wrapper
->netagent
.netagent_domain
,
720 sizeof(new_wrapper
->netagent
.netagent_domain
)) != 0 ||
721 memcmp(&session
->wrapper
->netagent
.netagent_type
, &new_wrapper
->netagent
.netagent_type
,
722 sizeof(new_wrapper
->netagent
.netagent_type
)) != 0) {
723 NETAGENTLOG0(LOG_ERR
, "Basic agent parameters do not match, cannot update");
724 FREE(new_wrapper
, M_NETAGENT
);
725 response_error
= NETAGENT_MESSAGE_ERROR_CANNOT_UPDATE
;
726 lck_rw_done(&netagent_lock
);
730 new_wrapper
->netagent
.netagent_flags
|= NETAGENT_FLAG_REGISTERED
;
731 if ((new_wrapper
->netagent
.netagent_flags
& NETAGENT_FLAG_ACTIVE
) &&
732 !(session
->wrapper
->netagent
.netagent_flags
& NETAGENT_FLAG_ACTIVE
)) {
733 netagent_active_count
++;
734 } else if (!(new_wrapper
->netagent
.netagent_flags
& NETAGENT_FLAG_ACTIVE
) &&
735 (session
->wrapper
->netagent
.netagent_flags
& NETAGENT_FLAG_ACTIVE
) &&
736 netagent_active_count
> 0) {
737 netagent_active_count
--;
740 LIST_REMOVE(session
->wrapper
, master_chain
);
741 FREE(session
->wrapper
, M_NETAGENT
);
742 session
->wrapper
= new_wrapper
;
743 new_wrapper
->control_unit
= session
->control_unit
;
744 LIST_INSERT_HEAD(&master_netagent_list
, new_wrapper
, master_chain
);
746 lck_rw_done(&netagent_lock
);
748 NETAGENTLOG0(LOG_DEBUG
, "Updated agent");
749 netagent_send_success_response(session
, NETAGENT_MESSAGE_TYPE_UPDATE
, message_id
);
750 netagent_post_event(new_wrapper
->netagent
.netagent_uuid
, KEV_NETAGENT_UPDATED
);
753 netagent_send_error_response(session
, NETAGENT_MESSAGE_TYPE_UPDATE
, message_id
, response_error
);
757 netagent_handle_get(struct netagent_session
*session
, u_int32_t message_id
,
758 u_int32_t payload_length
, mbuf_t packet
, int offset
)
760 #pragma unused(payload_length, packet, offset)
761 u_int8_t
*response
= NULL
;
762 u_int8_t
*cursor
= NULL
;
763 u_int32_t response_error
= NETAGENT_MESSAGE_ERROR_INTERNAL
;
765 if (session
== NULL
) {
766 NETAGENTLOG0(LOG_ERR
, "Failed to find session");
767 response_error
= NETAGENT_MESSAGE_ERROR_INTERNAL
;
771 if (session
->wrapper
== NULL
) {
772 NETAGENTLOG0(LOG_ERR
, "Session has no agent to get");
773 response_error
= NETAGENT_MESSAGE_ERROR_NOT_REGISTERED
;
777 lck_rw_lock_shared(&netagent_lock
);
779 size_t response_size
= sizeof(struct netagent_message_header
) + sizeof(session
->wrapper
->netagent
)
780 + session
->wrapper
->netagent
.netagent_data_size
;
781 MALLOC(response
, u_int8_t
*, response_size
, M_NETAGENT
, M_WAITOK
);
782 if (response
== NULL
) {
787 cursor
= netagent_buffer_write_message_header(cursor
, NETAGENT_MESSAGE_TYPE_GET
,
788 NETAGENT_MESSAGE_FLAGS_RESPONSE
, message_id
, 0,
789 response_size
- sizeof(struct netagent_message_header
));
790 memcpy(cursor
, &session
->wrapper
->netagent
, sizeof(session
->wrapper
->netagent
) +
791 session
->wrapper
->netagent
.netagent_data_size
);
793 lck_rw_done(&netagent_lock
);
795 if (!netagent_send_ctl_data(session
->control_unit
, (u_int8_t
*)response
, response_size
)) {
796 NETAGENTLOG0(LOG_ERR
, "Failed to send response");
798 FREE(response
, M_NETAGENT
);
801 netagent_send_error_response(session
, NETAGENT_MESSAGE_TYPE_GET
, message_id
, response_error
);
805 netagent_handle_assert(struct netagent_session
*session
, u_int32_t message_id
,
806 u_int32_t payload_length
, mbuf_t packet
, int offset
)
809 struct netagent_assertion
*new_assertion
= NULL
;
810 u_int32_t response_error
= NETAGENT_MESSAGE_ERROR_INTERNAL
;
811 uuid_t netagent_uuid
;
812 uuid_clear(netagent_uuid
);
814 if (session
== NULL
) {
815 NETAGENTLOG0(LOG_ERR
, "Failed to find session");
816 response_error
= NETAGENT_MESSAGE_ERROR_INTERNAL
;
820 if (payload_length
< sizeof(uuid_t
)) {
821 NETAGENTLOG(LOG_ERR
, "Assert message size too small for uuid: (%d < %d)",
822 payload_length
, sizeof(uuid_t
));
823 response_error
= NETAGENT_MESSAGE_ERROR_INVALID_DATA
;
827 error
= mbuf_copydata(packet
, offset
, sizeof(uuid_t
), &netagent_uuid
);
829 NETAGENTLOG(LOG_ERR
, "Failed to read uuid: %d", error
);
830 response_error
= NETAGENT_MESSAGE_ERROR_INTERNAL
;
834 MALLOC(new_assertion
, struct netagent_assertion
*, sizeof(*new_assertion
), M_NETAGENT
, M_WAITOK
);
835 if (new_assertion
== NULL
) {
836 NETAGENTLOG0(LOG_ERR
, "Failed to allocate assertion");
837 response_error
= NETAGENT_MESSAGE_ERROR_INTERNAL
;
841 uuid_copy(new_assertion
->asserted_uuid
, netagent_uuid
);
843 lck_rw_lock_shared(&netagent_lock
);
845 struct netagent_wrapper
*wrapper
= netagent_find_agent_with_uuid(netagent_uuid
);
846 if (wrapper
== NULL
) {
847 lck_rw_done(&netagent_lock
);
848 response_error
= NETAGENT_MESSAGE_ERROR_NOT_REGISTERED
;
849 FREE(new_assertion
, M_NETAGENT
);
853 error
= netagent_send_trigger(wrapper
, current_proc(), NETAGENT_TRIGGER_FLAG_USER
, NETAGENT_MESSAGE_TYPE_TRIGGER_ASSERT
);
855 lck_rw_done(&netagent_lock
);
856 NETAGENTLOG(LOG_ERR
, "Failed to trigger assert agent: %d", error
);
857 response_error
= NETAGENT_MESSAGE_ERROR_INTERNAL
;
858 FREE(new_assertion
, M_NETAGENT
);
862 LIST_INSERT_HEAD(&session
->assertion_list
, new_assertion
, assertion_chain
);
864 lck_rw_done(&netagent_lock
);
866 NETAGENTLOG0(LOG_DEBUG
, "Asserted agent");
867 netagent_send_success_response(session
, NETAGENT_MESSAGE_TYPE_ASSERT
, message_id
);
870 netagent_send_error_response(session
, NETAGENT_MESSAGE_TYPE_ASSERT
, message_id
, response_error
);
874 netagent_handle_unassert(struct netagent_session
*session
, u_int32_t message_id
,
875 u_int32_t payload_length
, mbuf_t packet
, int offset
)
878 u_int32_t response_error
= NETAGENT_MESSAGE_ERROR_INTERNAL
;
879 uuid_t netagent_uuid
;
880 uuid_clear(netagent_uuid
);
882 if (session
== NULL
) {
883 NETAGENTLOG0(LOG_ERR
, "Failed to find session");
884 response_error
= NETAGENT_MESSAGE_ERROR_INTERNAL
;
888 if (payload_length
< sizeof(uuid_t
)) {
889 NETAGENTLOG(LOG_ERR
, "Unassert message size too small for uuid: (%d < %d)",
890 payload_length
, sizeof(uuid_t
));
891 response_error
= NETAGENT_MESSAGE_ERROR_INVALID_DATA
;
895 error
= mbuf_copydata(packet
, offset
, sizeof(uuid_t
), &netagent_uuid
);
897 NETAGENTLOG(LOG_ERR
, "Failed to read uuid: %d", error
);
898 response_error
= NETAGENT_MESSAGE_ERROR_INTERNAL
;
902 struct netagent_assertion
*found_assertion
= NULL
;
903 struct netagent_assertion
*search_assertion
= NULL
;
904 LIST_FOREACH(search_assertion
, &session
->assertion_list
, assertion_chain
) {
905 if (uuid_compare(search_assertion
->asserted_uuid
, netagent_uuid
) == 0) {
906 found_assertion
= search_assertion
;
911 if (found_assertion
== NULL
) {
912 NETAGENTLOG0(LOG_ERR
, "Netagent uuid not previously asserted");
913 response_error
= NETAGENT_MESSAGE_ERROR_INVALID_DATA
;
917 LIST_REMOVE(found_assertion
, assertion_chain
);
918 FREE(found_assertion
, M_NETAGENT
);
919 found_assertion
= NULL
;
921 lck_rw_lock_shared(&netagent_lock
);
923 struct netagent_wrapper
*wrapper
= netagent_find_agent_with_uuid(netagent_uuid
);
924 if (wrapper
== NULL
) {
925 lck_rw_done(&netagent_lock
);
926 response_error
= NETAGENT_MESSAGE_ERROR_NOT_REGISTERED
;
930 error
= netagent_send_trigger(wrapper
, current_proc(), NETAGENT_TRIGGER_FLAG_USER
, NETAGENT_MESSAGE_TYPE_TRIGGER_UNASSERT
);
932 lck_rw_done(&netagent_lock
);
933 NETAGENTLOG(LOG_ERR
, "Failed to trigger assert agent: %d", error
);
934 response_error
= NETAGENT_MESSAGE_ERROR_INTERNAL
;
938 lck_rw_done(&netagent_lock
);
940 NETAGENTLOG0(LOG_DEBUG
, "Unasserted agent");
941 netagent_send_success_response(session
, NETAGENT_MESSAGE_TYPE_UNASSERT
, message_id
);
944 netagent_send_error_response(session
, NETAGENT_MESSAGE_TYPE_UNASSERT
, message_id
, response_error
);
947 static struct netagent_wrapper
*
948 netagent_find_agent_with_uuid(uuid_t uuid
)
950 struct netagent_wrapper
*search_netagent
= NULL
;
952 LIST_FOREACH(search_netagent
, &master_netagent_list
, master_chain
) {
953 if (uuid_compare(search_netagent
->netagent
.netagent_uuid
, uuid
) == 0) {
954 return (search_netagent
);
962 netagent_post_updated_interfaces(uuid_t uuid
)
964 struct netagent_wrapper
*wrapper
= NULL
;
965 lck_rw_lock_shared(&netagent_lock
);
966 wrapper
= netagent_find_agent_with_uuid(uuid
);
967 lck_rw_done(&netagent_lock
);
969 if (wrapper
!= NULL
) {
970 netagent_post_event(uuid
, KEV_NETAGENT_UPDATED_INTERFACES
);
972 NETAGENTLOG0(LOG_DEBUG
, "Interface event with no associated agent");
979 netagent_ioctl(u_long cmd
, caddr_t data
)
983 lck_rw_lock_shared(&netagent_lock
);
985 case SIOCGIFAGENTDATA32
: {
986 struct netagent_req32
*ifsir32
= (struct netagent_req32
*)(void *)data
;
987 struct netagent_wrapper
*wrapper
= netagent_find_agent_with_uuid(ifsir32
->netagent_uuid
);
988 if (wrapper
== NULL
) {
992 uuid_copy(ifsir32
->netagent_uuid
, wrapper
->netagent
.netagent_uuid
);
993 memcpy(ifsir32
->netagent_domain
, wrapper
->netagent
.netagent_domain
, sizeof(ifsir32
->netagent_domain
));
994 memcpy(ifsir32
->netagent_type
, wrapper
->netagent
.netagent_type
, sizeof(ifsir32
->netagent_type
));
995 memcpy(ifsir32
->netagent_desc
, wrapper
->netagent
.netagent_desc
, sizeof(ifsir32
->netagent_desc
));
996 ifsir32
->netagent_flags
= wrapper
->netagent
.netagent_flags
;
997 if (ifsir32
->netagent_data_size
== 0) {
998 // First pass, client wants data size
999 ifsir32
->netagent_data_size
= wrapper
->netagent
.netagent_data_size
;
1000 } else if (ifsir32
->netagent_data
!= USER_ADDR_NULL
&&
1001 ifsir32
->netagent_data_size
== wrapper
->netagent
.netagent_data_size
) {
1002 // Second pass, client wants data buffer filled out
1003 error
= copyout(wrapper
->netagent
.netagent_data
, ifsir32
->netagent_data
, wrapper
->netagent
.netagent_data_size
);
1009 case SIOCGIFAGENTDATA64
: {
1010 struct netagent_req64
*ifsir64
= (struct netagent_req64
*)(void *)data
;
1011 struct netagent_wrapper
*wrapper
= netagent_find_agent_with_uuid(ifsir64
->netagent_uuid
);
1012 if (wrapper
== NULL
) {
1016 uuid_copy(ifsir64
->netagent_uuid
, wrapper
->netagent
.netagent_uuid
);
1017 memcpy(ifsir64
->netagent_domain
, wrapper
->netagent
.netagent_domain
, sizeof(ifsir64
->netagent_domain
));
1018 memcpy(ifsir64
->netagent_type
, wrapper
->netagent
.netagent_type
, sizeof(ifsir64
->netagent_type
));
1019 memcpy(ifsir64
->netagent_desc
, wrapper
->netagent
.netagent_desc
, sizeof(ifsir64
->netagent_desc
));
1020 ifsir64
->netagent_flags
= wrapper
->netagent
.netagent_flags
;
1021 if (ifsir64
->netagent_data_size
== 0) {
1022 // First pass, client wants data size
1023 ifsir64
->netagent_data_size
= wrapper
->netagent
.netagent_data_size
;
1024 } else if (ifsir64
->netagent_data
!= USER_ADDR_NULL
&&
1025 ifsir64
->netagent_data_size
== wrapper
->netagent
.netagent_data_size
) {
1026 // Second pass, client wants data buffer filled out
1027 error
= copyout(wrapper
->netagent
.netagent_data
, ifsir64
->netagent_data
, wrapper
->netagent
.netagent_data_size
);
1038 lck_rw_done(&netagent_lock
);
1043 netagent_get_flags(uuid_t uuid
)
1045 u_int32_t flags
= 0;
1046 lck_rw_lock_shared(&netagent_lock
);
1047 struct netagent_wrapper
*wrapper
= netagent_find_agent_with_uuid(uuid
);
1048 if (wrapper
!= NULL
) {
1049 flags
= wrapper
->netagent
.netagent_flags
;
1051 NETAGENTLOG0(LOG_DEBUG
, "Flags requested for invalid netagent");
1053 lck_rw_done(&netagent_lock
);
1059 netagent_kernel_trigger(uuid_t uuid
)
1063 lck_rw_lock_shared(&netagent_lock
);
1064 struct netagent_wrapper
*wrapper
= netagent_find_agent_with_uuid(uuid
);
1065 if (wrapper
== NULL
) {
1066 NETAGENTLOG0(LOG_ERR
, "Requested netagent for kernel trigger could not be found");
1071 if ((wrapper
->netagent
.netagent_flags
& NETAGENT_FLAG_KERNEL_ACTIVATED
) == 0) {
1072 NETAGENTLOG0(LOG_ERR
, "Requested netagent for kernel trigger is not kernel activated");
1073 // Agent does not accept kernel triggers
1078 if ((wrapper
->netagent
.netagent_flags
& NETAGENT_FLAG_ACTIVE
)) {
1079 // Agent already active
1080 NETAGENTLOG0(LOG_INFO
, "Requested netagent for kernel trigger is already active");
1085 error
= netagent_send_trigger(wrapper
, current_proc(), NETAGENT_TRIGGER_FLAG_KERNEL
, NETAGENT_MESSAGE_TYPE_TRIGGER
);
1086 NETAGENTLOG((error
? LOG_ERR
: LOG_INFO
), "Triggered netagent from kernel (error %d)", error
);
1088 lck_rw_done(&netagent_lock
);
1093 netagent_trigger(struct proc
*p
, struct netagent_trigger_args
*uap
, int32_t *retval
)
1095 #pragma unused(p, retval)
1100 NETAGENTLOG0(LOG_ERR
, "uap == NULL");
1104 if (uap
->agent_uuid
) {
1105 if (uap
->agent_uuidlen
!= sizeof(uuid_t
)) {
1106 NETAGENTLOG(LOG_ERR
, "Incorrect length (got %d, expected %d)",
1107 uap
->agent_uuidlen
, sizeof(uuid_t
));
1111 error
= copyin(uap
->agent_uuid
, agent_uuid
, sizeof(uuid_t
));
1113 NETAGENTLOG(LOG_ERR
, "copyin error (%d)", error
);
1118 if (uuid_is_null(agent_uuid
)) {
1119 NETAGENTLOG0(LOG_ERR
, "Requested netagent UUID is empty");
1123 lck_rw_lock_shared(&netagent_lock
);
1124 struct netagent_wrapper
*wrapper
= netagent_find_agent_with_uuid(agent_uuid
);
1125 if (wrapper
== NULL
) {
1126 NETAGENTLOG0(LOG_ERR
, "Requested netagent UUID is not registered");
1131 if ((wrapper
->netagent
.netagent_flags
& NETAGENT_FLAG_USER_ACTIVATED
) == 0) {
1132 // Agent does not accept triggers
1133 NETAGENTLOG0(LOG_ERR
, "Requested netagent UUID is not eligible for triggering");
1138 if ((wrapper
->netagent
.netagent_flags
& NETAGENT_FLAG_ACTIVE
)) {
1139 // Agent already active
1140 NETAGENTLOG0(LOG_INFO
, "Requested netagent UUID is already active");
1145 error
= netagent_send_trigger(wrapper
, p
, NETAGENT_TRIGGER_FLAG_USER
, NETAGENT_MESSAGE_TYPE_TRIGGER
);
1146 NETAGENTLOG((error
? LOG_ERR
: LOG_INFO
), "Triggered netagent (error %d)", error
);
1148 lck_rw_done(&netagent_lock
);