1 /*
2 * Copyright (c) 2014-2024 Apple Inc. All rights reserved.
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 <sys/kernel.h>
36 #include <sys/kern_control.h>
37 #include <sys/mbuf.h>
38 #include <sys/kpi_mbuf.h>
39 #include <sys/sysctl.h>
40 #include <sys/priv.h>
41 #include <sys/kern_event.h>
42 #include <sys/sysproto.h>
43 #include <net/network_agent.h>
44 #include <net/if_var.h>
45 #include <net/necp.h>
46 #include <os/log.h>
47
48 u_int32_t netagent_debug = LOG_NOTICE; // 0=None, 1=Basic
49
50 SYSCTL_NODE(_net, OID_AUTO, netagent, CTLFLAG_RW | CTLFLAG_LOCKED, 0, "NetworkAgent");
51 SYSCTL_INT(_net_netagent, OID_AUTO, debug, CTLFLAG_LOCKED | CTLFLAG_RW, &netagent_debug, 0, "");
52
53 static int netagent_registered_count = 0;
54 SYSCTL_INT(_net_netagent, OID_AUTO, registered_count, CTLFLAG_RD | CTLFLAG_LOCKED,
55 &netagent_registered_count, 0, "");
56
57 static int netagent_active_count = 0;
58 SYSCTL_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 if (level == LOG_ERR) { \
64 os_log_error(OS_LOG_DEFAULT, "%s: " format "\n", __FUNCTION__, __VA_ARGS__); \
65 } else { \
66 os_log(OS_LOG_DEFAULT, "%s: " format "\n", __FUNCTION__, __VA_ARGS__); \
67 } \
68 } \
69 } while (0)
70
71 #define NETAGENTLOG0(level, msg) do { \
72 if (level <= netagent_debug) { \
73 if (level == LOG_ERR) { \
74 os_log_error(OS_LOG_DEFAULT, "%s: %s\n", __FUNCTION__, msg); \
75 } else { \
76 os_log(OS_LOG_DEFAULT, "%s: %s\n", __FUNCTION__, msg); \
77 } \
78 } \
79 } while (0)
80
81 #if __has_ptrcheck
82 static inline
83 __attribute__((always_inline)) __pure
84 uint8_t * __bidi_indexable
netagent_get_data(const struct netagent * agent)85 netagent_get_data(const struct netagent *agent)
86 {
87 if (agent == NULL) {
88 return NULL;
89 }
90
91 return __unsafe_forge_bidi_indexable(uint8_t *, agent->netagent_data, agent->netagent_data_size);
92 }
93 #else
94 #define netagent_get_data(agent) ((agent)->netagent_data)
95 #endif
96
97 #if __has_ptrcheck
98 static inline
99 __attribute__((always_inline)) __pure
100 uint8_t * __bidi_indexable
netagent_group_message_get_members(const struct netagent_client_group_message * msg,size_t members_length)101 netagent_group_message_get_members(const struct netagent_client_group_message *msg, size_t members_length)
102 {
103 if (msg == NULL) {
104 return NULL;
105 }
106
107 return __unsafe_forge_bidi_indexable(uint8_t *, msg->group_members, members_length);
108 }
109 #else
110 #define netagent_group_message_get_members(msg, members_length) ((msg)->group_members)
111 #endif
112
113 #if __has_ptrcheck
114 static inline
115 __attribute__((always_inline)) __pure
116 uint8_t * __bidi_indexable
netagent_assign_message_get_necp_result(const struct netagent_assign_nexus_message * msg,size_t result_length)117 netagent_assign_message_get_necp_result(const struct netagent_assign_nexus_message *msg, size_t result_length)
118 {
119 if (msg == NULL) {
120 return NULL;
121 }
122
123 return __unsafe_forge_bidi_indexable(uint8_t *, msg->assign_necp_results, result_length);
124 }
125 #else
126 #define netagent_assign_message_get_necp_result(msg, result_length) ((msg)->assign_necp_results)
127 #endif
128
129 struct netagent_client {
130 LIST_ENTRY(netagent_client) client_chain;
131 uuid_t client_id;
132 uuid_t client_proc_uuid;
133 pid_t client_pid;
134 };
135
136 LIST_HEAD(netagent_client_list_s, netagent_client);
137
138 struct netagent_token {
139 TAILQ_ENTRY(netagent_token) token_chain;
140 u_int32_t token_length;
141 u_int8_t * __indexable token_bytes;
142 };
143
144 TAILQ_HEAD(netagent_token_list_s, netagent_token);
145
146 #define NETAGENT_MAX_CLIENT_ERROR_COUNT 32
147
148 struct netagent_registration {
149 LIST_ENTRY(netagent_registration) global_chain;
150 TAILQ_ENTRY(netagent_registration) session_chain;
151 lck_rw_t agent_lock;
152 u_int32_t control_unit;
153 netagent_event_f event_handler;
154 void *event_context;
155 u_int32_t generation;
156 u_int64_t use_count;
157 u_int64_t need_tokens_event_deadline;
158 u_int32_t token_count;
159 u_int32_t token_low_water;
160 int32_t last_client_error;
161 u_int32_t client_error_count;
162 u_int8_t allow_multiple_registrations;
163 u_int8_t __pad_bytes[2];
164 struct netagent_token_list_s token_list;
165 struct netagent_client_list_s pending_triggers_list;
166 size_t netagent_alloc_size;
167 struct netagent *netagent __sized_by(netagent_alloc_size);
168 };
169
170 struct netagent_session {
171 u_int32_t control_unit; // A control unit of 0 indicates an agent owned by the kernel
172 lck_mtx_t session_lock;
173 TAILQ_HEAD(_netagent_registration_list, netagent_registration) registrations;
174
175 netagent_event_f event_handler;
176 void *event_context;
177 bool allow_multiple_registrations;
178 };
179
180 typedef enum {
181 kNetagentErrorDomainPOSIX = 0,
182 kNetagentErrorDomainUserDefined = 1,
183 } netagent_error_domain_t;
184
185 static LIST_HEAD(_netagent_list, netagent_registration) shared_netagent_list =
186 LIST_HEAD_INITIALIZER(master_netagent_list);
187
188 // Protected by netagent_list_lock
189 static u_int32_t g_next_generation = 1;
190
191 static kern_ctl_ref netagent_kctlref;
192 static u_int32_t netagent_family;
193 static LCK_GRP_DECLARE(netagent_mtx_grp, NETAGENT_CONTROL_NAME);
194 static LCK_RW_DECLARE(netagent_list_lock, &netagent_mtx_grp);
195
196 #define NETAGENT_LIST_LOCK_EXCLUSIVE() lck_rw_lock_exclusive(&netagent_list_lock)
197 #define NETAGENT_LIST_LOCK_SHARED() lck_rw_lock_shared(&netagent_list_lock)
198 #define NETAGENT_LIST_UNLOCK() lck_rw_done(&netagent_list_lock)
199 #define NETAGENT_LIST_ASSERT_LOCKED() LCK_RW_ASSERT(&netagent_list_lock, LCK_RW_ASSERT_HELD)
200
201 #define NETAGENT_SESSION_LOCK(session) lck_mtx_lock(&session->session_lock)
202 #define NETAGENT_SESSION_UNLOCK(session) lck_mtx_unlock(&session->session_lock)
203 #define NETAGENT_SESSION_ASSERT_LOCKED(session) LCK_MTX_ASSERT(&session->session_lock, LCK_MTX_ASSERT_OWNED)
204
205 #define NETAGENT_LOCK_EXCLUSIVE(registration) lck_rw_lock_exclusive(®istration->agent_lock)
206 #define NETAGENT_LOCK_SHARED(registration) lck_rw_lock_shared(®istration->agent_lock)
207 #define NETAGENT_LOCK_SHARED_TO_EXCLUSIVE(registration) lck_rw_lock_shared_to_exclusive(®istration->agent_lock)
208 #define NETAGENT_UNLOCK(registration) lck_rw_done(®istration->agent_lock)
209 #define NETAGENT_ASSERT_LOCKED(registration) LCK_RW_ASSERT(®istration->agent_lock, LCK_RW_ASSERT_HELD)
210
211 // Locking Notes
212
213 // Precedence, where 1 is the first lock that must be taken
214 // 1. NETAGENT_LIST_LOCK - protects shared_netagent_list
215 // 2. NETAGENT_SESSION_LOCK - protects the session->registrations list
216 // 3. NETAGENT_LOCK -> protects values in a registration
217
218 static errno_t netagent_register_control(void);
219 static errno_t netagent_ctl_connect(kern_ctl_ref kctlref, struct sockaddr_ctl *sac,
220 void **unitinfo);
221 static errno_t netagent_ctl_disconnect(kern_ctl_ref kctlref, u_int32_t unit, void *unitinfo);
222 static errno_t netagent_ctl_send(kern_ctl_ref kctlref, u_int32_t unit, void *unitinfo,
223 mbuf_t m, int flags);
224 static void netagent_ctl_rcvd(kern_ctl_ref kctlref, u_int32_t unit, void *unitinfo, int flags);
225 static errno_t netagent_ctl_getopt(kern_ctl_ref kctlref, u_int32_t unit, void *unitinfo,
226 int opt, void * __sized_by(*len)data, size_t *len);
227 static errno_t netagent_ctl_setopt(kern_ctl_ref kctlref, u_int32_t unit, void *unitinfo,
228 int opt, void * __sized_by(len)data, size_t len);
229
230 static int netagent_send_ctl_data(u_int32_t control_unit,
231 u_int8_t *__sized_by(buffer_size)buffer, size_t buffer_size);
232
233 static struct netagent_session *netagent_create_session(u_int32_t control_unit);
234 static void netagent_delete_session(struct netagent_session *session);
235
236 // Register
237 static void netagent_handle_register_message(struct netagent_session *session, u_int32_t message_id,
238 size_t payload_length, mbuf_t packet, size_t offset);
239 static errno_t netagent_handle_register_setopt(struct netagent_session *session, u_int8_t *payload,
240 size_t payload_length);
241
242 // Unregister
243 static void netagent_handle_unregister_message(struct netagent_session *session, u_int32_t message_id,
244 size_t payload_length, mbuf_t packet, size_t offset);
245 static errno_t netagent_handle_unregister_setopt(struct netagent_session *session, u_int8_t * __sized_by(payload_length)payload,
246 size_t payload_length);
247 static errno_t netagent_handle_unregister_all_setopt(struct netagent_session *session, u_int8_t * __sized_by(payload_length)payload,
248 size_t payload_length);
249
250 // Update
251 static void netagent_handle_update_message(struct netagent_session *session, u_int32_t message_id,
252 size_t payload_length, mbuf_t packet, size_t offset);
253 static errno_t netagent_handle_update_setopt(struct netagent_session *session, u_int8_t *payload,
254 size_t payload_length);
255
256 // Assign nexus
257 static void netagent_handle_assign_nexus_message(struct netagent_session *session, u_int32_t message_id,
258 size_t payload_length, mbuf_t packet, size_t offset);
259 static errno_t netagent_handle_assign_nexus_setopt(struct netagent_session *session, u_int8_t * __sized_by(payload_length)payload,
260 size_t payload_length);
261
262 // Assign group
263 static errno_t netagent_handle_assign_group_setopt(struct netagent_session *session, u_int8_t * __sized_by(payload_length)payload,
264 size_t payload_length);
265
266 // Set/get assert count
267 static errno_t netagent_handle_use_count_setopt(struct netagent_session *session, u_int8_t * __sized_by(payload_length)payload, size_t payload_length);
268 static errno_t netagent_handle_use_count_getopt(struct netagent_session *session, u_int8_t * __sized_by(*buffer_length)buffer, size_t *buffer_length);
269
270 // Manage tokens
271 static errno_t netagent_handle_add_token_setopt(struct netagent_session *session, u_int8_t * __sized_by(token_length)token, size_t token_length);
272 static errno_t netagent_handle_flush_tokens_setopt(struct netagent_session *session, u_int8_t * __sized_by(payload_length)payload, size_t payload_length);
273 static errno_t netagent_handle_token_count_getopt(struct netagent_session *session, u_int8_t * __sized_by(*buffer_length)buffer, size_t *buffer_length);
274 static errno_t netagent_handle_token_low_water_setopt(struct netagent_session *session, u_int8_t * __sized_by(buffer_length)buffer, size_t buffer_length);
275 static errno_t netagent_handle_token_low_water_getopt(struct netagent_session *session, u_int8_t * __sized_by(*buffer_length)buffer, size_t *buffer_length);
276
277 // Client error
278 static errno_t netagent_handle_reset_client_error_setopt(struct netagent_session *session, u_int8_t * __sized_by(payload_length)payload, size_t payload_length);
279
280 // Enable session mode
281 static errno_t netagent_handle_enable_session_mode_setopt(struct netagent_session *session, u_int8_t *payload, size_t payload_length);
282
283 // Requires list lock being held
284 static struct netagent_registration *netagent_find_agent_with_uuid_and_lock(uuid_t uuid, bool exclusively, bool ignore_lock);
285
286 // Requires session lock being held
287 static struct netagent_registration *
288 netagent_session_find_agent_with_uuid_and_lock(struct netagent_session *session, uuid_t uuid, bool exclusively, bool ignore_lock);
289
290 // Requires session lock being held, and single agent only
291 static struct netagent_registration *
292 netagent_session_access_agent_with_lock(struct netagent_session *session, bool exclusively, bool ignore_lock);
293
294 errno_t
netagent_init(void)295 netagent_init(void)
296 {
297 return netagent_register_control();
298 }
299
300 static errno_t
netagent_register_control(void)301 netagent_register_control(void)
302 {
303 struct kern_ctl_reg kern_ctl;
304 errno_t result = 0;
305
306 // Find a unique value for our interface family
307 result = mbuf_tag_id_find(NETAGENT_CONTROL_NAME, &netagent_family);
308 if (result != 0) {
309 NETAGENTLOG(LOG_ERR, "mbuf_tag_id_find_internal failed: %d", result);
310 return result;
311 }
312
313 bzero(&kern_ctl, sizeof(kern_ctl));
314 strlcpy(kern_ctl.ctl_name, NETAGENT_CONTROL_NAME, sizeof(kern_ctl.ctl_name));
315 kern_ctl.ctl_name[sizeof(kern_ctl.ctl_name) - 1] = 0;
316 kern_ctl.ctl_flags = CTL_FLAG_PRIVILEGED; // Require root
317 kern_ctl.ctl_sendsize = 64 * 1024;
318 kern_ctl.ctl_recvsize = 64 * 1024;
319 kern_ctl.ctl_connect = netagent_ctl_connect;
320 kern_ctl.ctl_disconnect = netagent_ctl_disconnect;
321 kern_ctl.ctl_send = netagent_ctl_send;
322 kern_ctl.ctl_rcvd = netagent_ctl_rcvd;
323 kern_ctl.ctl_setopt = netagent_ctl_setopt;
324 kern_ctl.ctl_getopt = netagent_ctl_getopt;
325
326 result = ctl_register(&kern_ctl, &netagent_kctlref);
327 if (result != 0) {
328 NETAGENTLOG(LOG_ERR, "ctl_register failed: %d", result);
329 return result;
330 }
331
332 return 0;
333 }
334
335 static errno_t
netagent_ctl_connect(kern_ctl_ref kctlref,struct sockaddr_ctl * sac,void ** unitinfo)336 netagent_ctl_connect(kern_ctl_ref kctlref, struct sockaddr_ctl *sac, void **unitinfo)
337 {
338 #pragma unused(kctlref)
339 *unitinfo = netagent_create_session(sac->sc_unit);
340 if (*unitinfo == NULL) {
341 // Could not allocate session
342 return ENOBUFS;
343 }
344
345 return 0;
346 }
347
348 static errno_t
netagent_ctl_disconnect(kern_ctl_ref kctlref,u_int32_t unit,void * unitinfo)349 netagent_ctl_disconnect(kern_ctl_ref kctlref, u_int32_t unit, void *unitinfo)
350 {
351 #pragma unused(kctlref, unit)
352 struct netagent_session *session = (struct netagent_session *)unitinfo;
353 if (session != NULL) {
354 netagent_delete_session(session);
355 }
356
357 return 0;
358 }
359
360 // Kernel events
361 static void
netagent_post_event(uuid_t agent_uuid,u_int32_t event_code,bool update_necp,bool should_update_immediately)362 netagent_post_event(uuid_t agent_uuid, u_int32_t event_code, bool update_necp, bool should_update_immediately)
363 {
364 if (update_necp) {
365 necp_update_all_clients_immediately_if_needed(should_update_immediately);
366 }
367
368 struct kev_msg ev_msg;
369 memset(&ev_msg, 0, sizeof(ev_msg));
370
371 struct kev_netagent_data event_data;
372
373 ev_msg.vendor_code = KEV_VENDOR_APPLE;
374 ev_msg.kev_class = KEV_NETWORK_CLASS;
375 ev_msg.kev_subclass = KEV_NETAGENT_SUBCLASS;
376 ev_msg.event_code = event_code;
377
378 uuid_copy(event_data.netagent_uuid, agent_uuid);
379 ev_msg.dv[0].data_ptr = &event_data;
380 ev_msg.dv[0].data_length = sizeof(event_data);
381
382 kev_post_msg(&ev_msg);
383 }
384
385 // Message handling
386 static u_int8_t * __indexable
387 netagent_buffer_write_message_header(u_int8_t * __sized_by(sizeof(struct netagent_message_header) + payload_length)buffer, u_int8_t message_type, u_int8_t flags, u_int32_t message_id, u_int32_t error, size_t payload_length)
388 {
389 memset(buffer, 0, sizeof(struct netagent_message_header));
390 ((struct netagent_message_header *)(void *)buffer)->message_type = message_type;
391 ((struct netagent_message_header *)(void *)buffer)->message_flags = flags;
392 ((struct netagent_message_header *)(void *)buffer)->message_id = message_id;
393 ((struct netagent_message_header *)(void *)buffer)->message_error = error;
394 ((struct netagent_message_header *)(void *)buffer)->message_payload_length = (u_int32_t)payload_length;
395 return payload_length ? buffer + sizeof(struct netagent_message_header) : NULL;
396 }
397
398 static u_int8_t * __indexable
399 netagent_buffer_write_session_message_header(u_int8_t * __sized_by(sizeof(struct netagent_session_message_header) + payload_length)buffer, u_int8_t message_type, u_int8_t flags, u_int32_t message_id, u_int32_t error, uuid_t message_agent_id, size_t payload_length)
400 {
401 memset(buffer, 0, sizeof(struct netagent_session_message_header));
402 ((struct netagent_session_message_header *)(void *)buffer)->message_type = message_type;
403 ((struct netagent_session_message_header *)(void *)buffer)->message_flags = flags;
404 ((struct netagent_session_message_header *)(void *)buffer)->message_id = message_id;
405 ((struct netagent_session_message_header *)(void *)buffer)->message_error = error;
406 uuid_copy(((struct netagent_session_message_header *)(void *)buffer)->message_agent_id, message_agent_id);
407 ((struct netagent_session_message_header *)(void *)buffer)->message_payload_length = (u_int32_t)payload_length;
408 return payload_length ? buffer + sizeof(struct netagent_session_message_header) : NULL;
409 }
410
411 static int
netagent_send_ctl_data(u_int32_t control_unit,u_int8_t * __sized_by (buffer_size)buffer,size_t buffer_size)412 netagent_send_ctl_data(u_int32_t control_unit, u_int8_t *__sized_by(buffer_size) buffer, size_t buffer_size)
413 {
414 if (netagent_kctlref == NULL || control_unit == 0 || buffer == NULL || buffer_size == 0) {
415 return EINVAL;
416 }
417
418 return ctl_enqueuedata(netagent_kctlref, control_unit, buffer, buffer_size, CTL_DATA_EOR);
419 }
420
421 static int
netagent_send_trigger(struct netagent_registration * registration,struct proc * p,u_int32_t flags,u_int8_t trigger_type)422 netagent_send_trigger(struct netagent_registration *registration, struct proc *p, u_int32_t flags, u_int8_t trigger_type)
423 {
424 int error = 0;
425 struct netagent_trigger_message *trigger_message = NULL;
426 const bool session_mode = registration->allow_multiple_registrations;
427 const size_t header_size = (session_mode ? sizeof(struct netagent_session_message_header) : sizeof(struct netagent_message_header));
428 u_int8_t *trigger = NULL;
429 size_t trigger_size = header_size + sizeof(struct netagent_trigger_message);
430 trigger = (u_int8_t *)kalloc_data(trigger_size, Z_WAITOK);
431 if (trigger == NULL) {
432 return ENOMEM;
433 }
434
435 if (session_mode) {
436 (void)netagent_buffer_write_session_message_header(trigger, trigger_type, 0, 0, 0, registration->netagent->netagent_uuid, sizeof(struct netagent_trigger_message));
437 } else {
438 (void)netagent_buffer_write_message_header(trigger, trigger_type, 0, 0, 0, sizeof(struct netagent_trigger_message));
439 }
440
441 trigger_message = (struct netagent_trigger_message *)(void *)(trigger + header_size);
442 trigger_message->trigger_flags = flags;
443 if (p != NULL) {
444 trigger_message->trigger_pid = proc_pid(p);
445 proc_getexecutableuuid(p, trigger_message->trigger_proc_uuid, sizeof(trigger_message->trigger_proc_uuid));
446 } else {
447 trigger_message->trigger_pid = 0;
448 uuid_clear(trigger_message->trigger_proc_uuid);
449 }
450
451 if ((error = netagent_send_ctl_data(registration->control_unit, trigger, trigger_size))) {
452 NETAGENTLOG(LOG_ERR, "Failed to send trigger message on control unit %d", registration->control_unit);
453 }
454
455 kfree_data(trigger, trigger_size);
456 return error;
457 }
458
459 static int
netagent_send_client_message(struct netagent_registration * registration,uuid_t client_id,u_int8_t message_type)460 netagent_send_client_message(struct netagent_registration *registration, uuid_t client_id, u_int8_t message_type)
461 {
462 int error = 0;
463 struct netagent_client_message *client_message = NULL;
464 const bool session_mode = registration->allow_multiple_registrations;
465 const size_t header_size = (session_mode ? sizeof(struct netagent_session_message_header) : sizeof(struct netagent_message_header));
466 u_int8_t *message = NULL;
467 size_t message_size = header_size + sizeof(struct netagent_client_message);
468
469 message = (u_int8_t *)kalloc_data(message_size, Z_WAITOK);
470 if (message == NULL) {
471 return ENOMEM;
472 }
473
474 if (session_mode) {
475 (void)netagent_buffer_write_session_message_header(message, message_type, 0, 0, 0, registration->netagent->netagent_uuid, sizeof(struct netagent_client_message));
476 } else {
477 (void)netagent_buffer_write_message_header(message, message_type, 0, 0, 0, sizeof(struct netagent_client_message));
478 }
479
480 client_message = (struct netagent_client_message *)(void *)(message + header_size);
481 uuid_copy(client_message->client_id, client_id);
482
483 if ((error = netagent_send_ctl_data(registration->control_unit, message, message_size))) {
484 NETAGENTLOG(LOG_ERR, "Failed to send client message %d on control unit %d", message_type, registration->control_unit);
485 }
486
487 kfree_data(message, message_size);
488 return error;
489 }
490
491 static int
netagent_send_error_message(struct netagent_registration * registration,uuid_t client_id,u_int8_t message_type,int32_t error_code)492 netagent_send_error_message(struct netagent_registration *registration, uuid_t client_id, u_int8_t message_type, int32_t error_code)
493 {
494 int error = 0;
495 struct netagent_client_error_message *client_message = NULL;
496 const bool session_mode = registration->allow_multiple_registrations;
497 const size_t header_size = (session_mode ? sizeof(struct netagent_session_message_header) : sizeof(struct netagent_message_header));
498 u_int8_t *message = NULL;
499 size_t message_size = header_size + sizeof(struct netagent_client_error_message);
500
501 message = (u_int8_t *)kalloc_data(message_size, Z_WAITOK);
502 if (message == NULL) {
503 return ENOMEM;
504 }
505
506 if (session_mode) {
507 (void)netagent_buffer_write_session_message_header(message, message_type, 0, 0, 0, registration->netagent->netagent_uuid, sizeof(struct netagent_client_error_message));
508 } else {
509 (void)netagent_buffer_write_message_header(message, message_type, 0, 0, 0, sizeof(struct netagent_client_error_message));
510 }
511
512 client_message = (struct netagent_client_error_message *)(void *)(message + header_size);
513 uuid_copy(client_message->client_id, client_id);
514 client_message->error_code = error_code;
515
516 if ((error = netagent_send_ctl_data(registration->control_unit, message, message_size))) {
517 NETAGENTLOG(LOG_ERR, "Failed to send client message %d on control unit %d", message_type, registration->control_unit);
518 }
519
520 kfree_data(message, message_size);
521 return error;
522 }
523
524 static int
netagent_send_group_message(struct netagent_registration * registration,uuid_t client_id,u_int8_t message_type,struct necp_client_group_members * group_members)525 netagent_send_group_message(struct netagent_registration *registration, uuid_t client_id, u_int8_t message_type, struct necp_client_group_members *group_members)
526 {
527 int error = 0;
528 struct netagent_client_group_message * __single client_message = NULL;
529 const bool session_mode = registration->allow_multiple_registrations;
530 const size_t header_size = (session_mode ? sizeof(struct netagent_session_message_header) : sizeof(struct netagent_message_header));
531 u_int8_t *message = NULL;
532 size_t message_size = header_size + sizeof(struct netagent_client_group_message) + group_members->group_members_length;
533
534 message = (u_int8_t *)kalloc_data(message_size, Z_WAITOK);
535 if (message == NULL) {
536 return ENOMEM;
537 }
538
539 if (session_mode) {
540 (void)netagent_buffer_write_session_message_header(message, message_type, 0, 0, 0, registration->netagent->netagent_uuid, sizeof(struct netagent_client_group_message) + group_members->group_members_length);
541 } else {
542 (void)netagent_buffer_write_message_header(message, message_type, 0, 0, 0, sizeof(struct netagent_client_group_message) + group_members->group_members_length);
543 }
544
545 client_message = (struct netagent_client_group_message *)(void *)(message + header_size);
546 uuid_copy(client_message->client_id, client_id);
547 memcpy(netagent_group_message_get_members(client_message, group_members->group_members_length), group_members->group_members, group_members->group_members_length);
548
549 if ((error = netagent_send_ctl_data(registration->control_unit, message, message_size))) {
550 NETAGENTLOG(LOG_ERR, "Failed to send client group message %d on control unit %d", message_type, registration->control_unit);
551 }
552
553 kfree_data(message, message_size);
554 return error;
555 }
556
557 static int
netagent_send_tokens_needed(struct netagent_registration * registration)558 netagent_send_tokens_needed(struct netagent_registration *registration)
559 {
560 const u_int8_t message_type = NETAGENT_MESSAGE_TYPE_TOKENS_NEEDED;
561 int error = 0;
562 u_int8_t *message = NULL;
563 const bool session_mode = registration->allow_multiple_registrations;
564 const size_t header_size = (session_mode ? sizeof(struct netagent_session_message_header) : sizeof(struct netagent_message_header));
565 size_t message_size = header_size;
566
567 message = (u_int8_t *)kalloc_data(message_size, Z_WAITOK);
568 if (message == NULL) {
569 return ENOMEM;
570 }
571
572 if (session_mode) {
573 (void)netagent_buffer_write_session_message_header(message, message_type, 0, 0, 0, registration->netagent->netagent_uuid, 0);
574 } else {
575 (void)netagent_buffer_write_message_header(message, message_type, 0, 0, 0, 0);
576 }
577
578 if ((error = netagent_send_ctl_data(registration->control_unit, message, message_size))) {
579 NETAGENTLOG(LOG_ERR, "Failed to send client tokens needed message on control unit %d", registration->control_unit);
580 }
581
582 kfree_data(message, message_size);
583 return error;
584 }
585
586 static int
netagent_send_success_response(struct netagent_session * session,u_int8_t message_type,u_int32_t message_id)587 netagent_send_success_response(struct netagent_session *session, u_int8_t message_type, u_int32_t message_id)
588 {
589 int error = 0;
590 u_int8_t *response = NULL;
591 size_t response_size = sizeof(struct netagent_message_header);
592
593 response = (u_int8_t *)kalloc_data(response_size, Z_WAITOK);
594 if (response == NULL) {
595 return ENOMEM;
596 }
597 (void)netagent_buffer_write_message_header(response, message_type, NETAGENT_MESSAGE_FLAGS_RESPONSE, message_id, 0, 0);
598
599 if ((error = netagent_send_ctl_data(session->control_unit, response, response_size))) {
600 NETAGENTLOG0(LOG_ERR, "Failed to send response");
601 }
602
603 kfree_data(response, response_size);
604 return error;
605 }
606
607 static errno_t
netagent_send_error_response(struct netagent_session * session,u_int8_t message_type,u_int32_t message_id,u_int32_t error_code)608 netagent_send_error_response(struct netagent_session *session, u_int8_t message_type,
609 u_int32_t message_id, u_int32_t error_code)
610 {
611 int error = 0;
612 u_int8_t *response = NULL;
613 size_t response_size = sizeof(struct netagent_message_header);
614
615 if (session == NULL) {
616 NETAGENTLOG0(LOG_ERR, "Got a NULL session");
617 return EINVAL;
618 }
619
620 response = (u_int8_t *)kalloc_data(response_size, Z_WAITOK);
621 if (response == NULL) {
622 return ENOMEM;
623 }
624 (void)netagent_buffer_write_message_header(response, message_type, NETAGENT_MESSAGE_FLAGS_RESPONSE,
625 message_id, error_code, 0);
626
627 if ((error = netagent_send_ctl_data(session->control_unit, response, response_size))) {
628 NETAGENTLOG0(LOG_ERR, "Failed to send response");
629 }
630
631 kfree_data(response, response_size);
632 return error;
633 }
634
635 static errno_t
netagent_ctl_send(kern_ctl_ref kctlref,u_int32_t unit,void * unitinfo,mbuf_t packet,int flags)636 netagent_ctl_send(kern_ctl_ref kctlref, u_int32_t unit, void *unitinfo, mbuf_t packet, int flags)
637 {
638 #pragma unused(kctlref, unit, flags)
639 struct netagent_session *session = (struct netagent_session *)unitinfo;
640 struct netagent_message_header header;
641 int error = 0;
642
643 if (session == NULL) {
644 NETAGENTLOG0(LOG_ERR, "Got a NULL session");
645 error = EINVAL;
646 goto done;
647 }
648
649 if (mbuf_pkthdr_len(packet) < sizeof(header)) {
650 NETAGENTLOG(LOG_ERR, "Got a bad packet, length (%lu) < sizeof header (%lu)",
651 mbuf_pkthdr_len(packet), sizeof(header));
652 error = EINVAL;
653 goto done;
654 }
655
656 error = mbuf_copydata(packet, 0, sizeof(header), &header);
657 if (error) {
658 NETAGENTLOG(LOG_ERR, "mbuf_copydata failed for the header: %d", error);
659 error = ENOBUFS;
660 goto done;
661 }
662
663 switch (header.message_type) {
664 case NETAGENT_MESSAGE_TYPE_REGISTER: {
665 netagent_handle_register_message(session, header.message_id, header.message_payload_length,
666 packet, sizeof(header));
667 break;
668 }
669 case NETAGENT_MESSAGE_TYPE_UNREGISTER: {
670 netagent_handle_unregister_message(session, header.message_id, header.message_payload_length,
671 packet, sizeof(header));
672 break;
673 }
674 case NETAGENT_MESSAGE_TYPE_UPDATE: {
675 netagent_handle_update_message(session, header.message_id, header.message_payload_length,
676 packet, sizeof(header));
677 break;
678 }
679 case NETAGENT_MESSAGE_TYPE_GET: {
680 NETAGENTLOG0(LOG_ERR, "NETAGENT_MESSAGE_TYPE_GET no longer supported");
681 break;
682 }
683 case NETAGENT_MESSAGE_TYPE_ASSERT: {
684 NETAGENTLOG0(LOG_ERR, "NETAGENT_MESSAGE_TYPE_ASSERT no longer supported");
685 break;
686 }
687 case NETAGENT_MESSAGE_TYPE_UNASSERT: {
688 NETAGENTLOG0(LOG_ERR, "NETAGENT_MESSAGE_TYPE_UNASSERT no longer supported");
689 break;
690 }
691 case NETAGENT_MESSAGE_TYPE_ASSIGN_NEXUS: {
692 netagent_handle_assign_nexus_message(session, header.message_id, header.message_payload_length,
693 packet, sizeof(header));
694 break;
695 }
696 default: {
697 NETAGENTLOG(LOG_ERR, "Received unknown message type %d", header.message_type);
698 netagent_send_error_response(session, header.message_type, header.message_id,
699 NETAGENT_MESSAGE_ERROR_UNKNOWN_TYPE);
700 break;
701 }
702 }
703
704 done:
705 mbuf_freem(packet);
706 return error;
707 }
708
709 static void
netagent_ctl_rcvd(kern_ctl_ref kctlref,u_int32_t unit,void * unitinfo,int flags)710 netagent_ctl_rcvd(kern_ctl_ref kctlref, u_int32_t unit, void *unitinfo, int flags)
711 {
712 #pragma unused(kctlref, unit, unitinfo, flags)
713 return;
714 }
715
716 static errno_t
netagent_ctl_getopt(kern_ctl_ref kctlref,u_int32_t unit,void * unitinfo,int opt,void * __sized_by (* len)data,size_t * len)717 netagent_ctl_getopt(kern_ctl_ref kctlref, u_int32_t unit, void *unitinfo, int opt,
718 void * __sized_by(*len)data, size_t *len)
719 {
720 #pragma unused(kctlref, unit)
721 struct netagent_session *session = (struct netagent_session *)unitinfo;
722 errno_t error;
723
724 if (session == NULL) {
725 NETAGENTLOG0(LOG_ERR, "Received a NULL session");
726 error = EINVAL;
727 goto done;
728 }
729
730 switch (opt) {
731 case NETAGENT_OPTION_TYPE_USE_COUNT: {
732 NETAGENTLOG0(LOG_DEBUG, "Request to get use count");
733 error = netagent_handle_use_count_getopt(session, data, len);
734 break;
735 }
736 case NETAGENT_OPTION_TYPE_TOKEN_COUNT: {
737 NETAGENTLOG0(LOG_DEBUG, "Request to get token count");
738 error = netagent_handle_token_count_getopt(session, data, len);
739 break;
740 }
741 case NETAGENT_OPTION_TYPE_TOKEN_LOW_WATER: {
742 NETAGENTLOG0(LOG_DEBUG, "Request to get token low water mark");
743 error = netagent_handle_token_low_water_getopt(session, data, len);
744 break;
745 }
746 default:
747 NETAGENTLOG0(LOG_ERR, "Received unknown option");
748 error = ENOPROTOOPT;
749 break;
750 }
751
752 done:
753 return error;
754 }
755
756 static errno_t
netagent_ctl_setopt(kern_ctl_ref kctlref,u_int32_t unit,void * unitinfo,int opt,void * __sized_by (len)data,size_t len)757 netagent_ctl_setopt(kern_ctl_ref kctlref, u_int32_t unit, void *unitinfo, int opt,
758 void * __sized_by(len)data, size_t len)
759 {
760 #pragma unused(kctlref, unit)
761 struct netagent_session *session = (struct netagent_session *)unitinfo;
762 errno_t error;
763
764 if (session == NULL) {
765 NETAGENTLOG0(LOG_ERR, "Received a NULL session");
766 error = EINVAL;
767 goto done;
768 }
769
770 switch (opt) {
771 case NETAGENT_OPTION_TYPE_REGISTER: {
772 NETAGENTLOG0(LOG_DEBUG, "Request for registration");
773 error = netagent_handle_register_setopt(session, data, len);
774 break;
775 }
776 case NETAGENT_OPTION_TYPE_UPDATE: {
777 NETAGENTLOG0(LOG_DEBUG, "Request for update");
778 error = netagent_handle_update_setopt(session, data, len);
779 break;
780 }
781 case NETAGENT_OPTION_TYPE_UNREGISTER: {
782 NETAGENTLOG0(LOG_DEBUG, "Request for unregistration");
783 error = netagent_handle_unregister_setopt(session, data, len);
784 break;
785 }
786 case NETAGENT_OPTION_TYPE_ASSIGN_NEXUS: {
787 NETAGENTLOG0(LOG_DEBUG, "Request for assigning nexus");
788 error = netagent_handle_assign_nexus_setopt(session, data, len);
789 break;
790 }
791 case NETAGENT_MESSAGE_TYPE_ASSIGN_GROUP_MEMBERS: {
792 NETAGENTLOG0(LOG_DEBUG, "Request for assigning group members");
793 error = netagent_handle_assign_group_setopt(session, data, len);
794 break;
795 }
796 case NETAGENT_OPTION_TYPE_USE_COUNT: {
797 NETAGENTLOG0(LOG_DEBUG, "Request to set use count");
798 error = netagent_handle_use_count_setopt(session, data, len);
799 break;
800 }
801 case NETAGENT_OPTION_TYPE_ADD_TOKEN: {
802 NETAGENTLOG0(LOG_DEBUG, "Request to add a token");
803 error = netagent_handle_add_token_setopt(session, data, len);
804 break;
805 }
806 case NETAGENT_OPTION_TYPE_FLUSH_TOKENS: {
807 NETAGENTLOG0(LOG_DEBUG, "Request to flush tokens");
808 error = netagent_handle_flush_tokens_setopt(session, data, len);
809 break;
810 }
811 case NETAGENT_OPTION_TYPE_TOKEN_LOW_WATER: {
812 NETAGENTLOG0(LOG_DEBUG, "Request to set token low water mark");
813 error = netagent_handle_token_low_water_setopt(session, data, len);
814 break;
815 }
816 case NETAGENT_OPTION_TYPE_RESET_CLIENT_ERROR: {
817 NETAGENTLOG0(LOG_DEBUG, "Request to reset client error");
818 error = netagent_handle_reset_client_error_setopt(session, data, len);
819 break;
820 }
821 case NETAGENT_OPTION_TYPE_ENABLE_SESSION_MODE: {
822 NETAGENTLOG0(LOG_DEBUG, "Request to enable session mode");
823 error = netagent_handle_enable_session_mode_setopt(session, data, len);
824 break;
825 }
826 case NETAGENT_OPTION_TYPE_UNREGISTER_ALL: {
827 NETAGENTLOG0(LOG_DEBUG, "Request for unregistration of all agents");
828 error = netagent_handle_unregister_all_setopt(session, data, len);
829 break;
830 }
831 default:
832 NETAGENTLOG0(LOG_ERR, "Received unknown option");
833 error = ENOPROTOOPT;
834 break;
835 }
836
837 done:
838 return error;
839 }
840
841 // Session Management
842 static struct netagent_session *
netagent_create_session(u_int32_t control_unit)843 netagent_create_session(u_int32_t control_unit)
844 {
845 struct netagent_session *new_session = NULL;
846
847 new_session = kalloc_type(struct netagent_session,
848 Z_WAITOK | Z_ZERO | Z_NOFAIL);
849 NETAGENTLOG(LOG_DEBUG, "Create agent session, control unit %d", control_unit);
850 new_session->control_unit = control_unit;
851 lck_mtx_init(&new_session->session_lock, &netagent_mtx_grp, LCK_ATTR_NULL);
852 TAILQ_INIT(&new_session->registrations);
853
854 return new_session;
855 }
856
857 netagent_session_t
netagent_create(netagent_event_f event_handler,void * context)858 netagent_create(netagent_event_f event_handler, void *context)
859 {
860 struct netagent_session *session = netagent_create_session(0);
861 if (session == NULL) {
862 return NULL;
863 }
864
865 session->event_handler = event_handler;
866 session->event_context = context;
867 return session;
868 }
869
870 static void
netagent_token_free(struct netagent_token * token)871 netagent_token_free(struct netagent_token *token)
872 {
873 kfree_data(token->token_bytes, token->token_length);
874 kfree_type(struct netagent_token, token);
875 }
876
877 static struct netagent_registration *
netagent_alloc_registration_memory(uint32_t data_size)878 netagent_alloc_registration_memory(uint32_t data_size)
879 {
880 struct netagent_registration *new_registration;
881 size_t netagent_alloc_size = sizeof(struct netagent) + data_size;
882
883 new_registration = kalloc_type(struct netagent_registration,
884 Z_WAITOK | Z_ZERO | Z_NOFAIL);
885 new_registration->netagent = kalloc_data(netagent_alloc_size, Z_WAITOK | Z_NOFAIL);
886 new_registration->netagent_alloc_size = netagent_alloc_size;
887
888 lck_rw_init(&new_registration->agent_lock, &netagent_mtx_grp, LCK_ATTR_NULL);
889
890 return new_registration;
891 }
892
893 static void
netagent_free_registration_memory(struct netagent_registration * registration)894 netagent_free_registration_memory(struct netagent_registration *registration)
895 {
896 // Before destroying the lock, take the lock exclusively and then
897 // drop it again. This ensures that no other thread was holding
898 // onto the lock at the time of destroying it.
899 // This can happen in netagent_client_message_with_params due
900 // to the fact that the registration lock needs to be held during the
901 // event callout, while the list lock has been released. Taking
902 // this lock here ensures that any such remaining thread completes
903 // before this object is released. Since the registration object has
904 // already been removed from any and all lists by this point,
905 // there isn't any way for a new thread to start referencing it.
906 NETAGENT_LOCK_EXCLUSIVE(registration);
907 NETAGENT_UNLOCK(registration);
908 lck_rw_destroy(®istration->agent_lock, &netagent_mtx_grp);
909
910 kfree_data_sized_by(registration->netagent, registration->netagent_alloc_size);
911 kfree_type(struct netagent_registration, registration);
912 }
913
914 static void
netagent_free_registration(struct netagent_registration * registration)915 netagent_free_registration(struct netagent_registration *registration)
916 {
917 // Free any leftover tokens
918 struct netagent_token *search_token = NULL;
919 struct netagent_token *temp_token = NULL;
920 TAILQ_FOREACH_SAFE(search_token, ®istration->token_list, token_chain, temp_token) {
921 TAILQ_REMOVE(®istration->token_list, search_token, token_chain);
922 netagent_token_free(search_token);
923 }
924
925 // Free any pending client triggers
926 struct netagent_client * __single search_client = NULL;
927 struct netagent_client *temp_client = NULL;
928 LIST_FOREACH_SAFE(search_client, ®istration->pending_triggers_list, client_chain, temp_client) {
929 LIST_REMOVE(search_client, client_chain);
930 kfree_type(struct netagent_client, search_client);
931 }
932
933 // Free registration itself
934 netagent_free_registration_memory(registration);
935 }
936
937 static void
netagent_unregister_all_session_registrations(struct netagent_session * session)938 netagent_unregister_all_session_registrations(struct netagent_session *session)
939 {
940 TAILQ_HEAD(_netagent_registration_list, netagent_registration) deleting_registrations;
941 TAILQ_INIT(&deleting_registrations);
942 NETAGENT_LIST_LOCK_EXCLUSIVE();
943 if (session != NULL) {
944 NETAGENT_SESSION_LOCK(session);
945 struct netagent_registration *registration = NULL;
946 struct netagent_registration *temp_registration = NULL;
947 TAILQ_FOREACH_SAFE(registration, &session->registrations, session_chain, temp_registration) {
948 if (netagent_registered_count > 0) {
949 netagent_registered_count--;
950 }
951 if ((registration->netagent->netagent_flags & NETAGENT_FLAG_ACTIVE) &&
952 netagent_active_count > 0) {
953 netagent_active_count--;
954 }
955
956 LIST_REMOVE(registration, global_chain);
957 TAILQ_REMOVE(&session->registrations, registration, session_chain);
958 TAILQ_INSERT_TAIL(&deleting_registrations, registration, session_chain);
959 NETAGENTLOG0(LOG_DEBUG, "Unregistered agent");
960 }
961 NETAGENT_SESSION_UNLOCK(session);
962 }
963 NETAGENT_LIST_UNLOCK();
964
965 struct netagent_registration *registration = NULL;
966 struct netagent_registration *temp_registration = NULL;
967 TAILQ_FOREACH_SAFE(registration, &deleting_registrations, session_chain, temp_registration) {
968 TAILQ_REMOVE(&deleting_registrations, registration, session_chain);
969
970 ifnet_clear_netagent(registration->netagent->netagent_uuid);
971 netagent_post_event(registration->netagent->netagent_uuid, KEV_NETAGENT_UNREGISTERED, TRUE, false);
972
973 netagent_free_registration(registration);
974 }
975 }
976
977 static void
netagent_unregister_one_session_registration(struct netagent_session * session,uuid_t agent_id)978 netagent_unregister_one_session_registration(struct netagent_session *session, uuid_t agent_id)
979 {
980 bool unregistered = false;
981 NETAGENT_LIST_LOCK_EXCLUSIVE();
982 if (session != NULL) {
983 NETAGENT_SESSION_LOCK(session);
984 struct netagent_registration *registration = NULL;
985 struct netagent_registration *temp_registration = NULL;
986 TAILQ_FOREACH_SAFE(registration, &session->registrations, session_chain, temp_registration) {
987 if (uuid_compare(agent_id, registration->netagent->netagent_uuid) != 0) {
988 // Not a match, skip
989 continue;
990 }
991
992 if (netagent_registered_count > 0) {
993 netagent_registered_count--;
994 }
995 if ((registration->netagent->netagent_flags & NETAGENT_FLAG_ACTIVE) &&
996 netagent_active_count > 0) {
997 netagent_active_count--;
998 }
999
1000 LIST_REMOVE(registration, global_chain);
1001 TAILQ_REMOVE(&session->registrations, registration, session_chain);
1002
1003 unregistered = true;
1004 netagent_free_registration(registration);
1005
1006 NETAGENTLOG0(LOG_DEBUG, "Unregistered agent");
1007 }
1008 NETAGENT_SESSION_UNLOCK(session);
1009 }
1010 NETAGENT_LIST_UNLOCK();
1011
1012 if (unregistered) {
1013 ifnet_clear_netagent(agent_id);
1014 netagent_post_event(agent_id, KEV_NETAGENT_UNREGISTERED, TRUE, false);
1015 }
1016 }
1017
1018 static void
netagent_delete_session(struct netagent_session * session)1019 netagent_delete_session(struct netagent_session *session)
1020 {
1021 if (session != NULL) {
1022 netagent_unregister_all_session_registrations(session);
1023 lck_mtx_destroy(&session->session_lock, &netagent_mtx_grp);
1024 kfree_type(struct netagent_session, session);
1025 }
1026 }
1027
1028 void
netagent_destroy(netagent_session_t session)1029 netagent_destroy(netagent_session_t session)
1030 {
1031 return netagent_delete_session((struct netagent_session *)session);
1032 }
1033
1034 static size_t
netagent_packet_get_netagent_data_size(mbuf_t packet,size_t offset,int * err)1035 netagent_packet_get_netagent_data_size(mbuf_t packet, size_t offset, int *err)
1036 {
1037 int error = 0;
1038
1039 struct netagent netagent_peek;
1040 memset(&netagent_peek, 0, sizeof(netagent_peek));
1041
1042 *err = 0;
1043
1044 error = mbuf_copydata(packet, offset, sizeof(netagent_peek), &netagent_peek);
1045 if (error) {
1046 *err = ENOENT;
1047 return 0;
1048 }
1049
1050 return netagent_peek.netagent_data_size;
1051 }
1052
1053 static errno_t
netagent_handle_register_inner(struct netagent_session * session,struct netagent_registration * new_registration)1054 netagent_handle_register_inner(struct netagent_session *session, struct netagent_registration *new_registration)
1055 {
1056 NETAGENT_LIST_LOCK_EXCLUSIVE();
1057
1058 NETAGENT_SESSION_LOCK(session);
1059
1060 if (!session->allow_multiple_registrations && !TAILQ_EMPTY(&session->registrations)) {
1061 NETAGENT_SESSION_UNLOCK(session);
1062 NETAGENT_LIST_UNLOCK();
1063 return EINVAL;
1064 }
1065
1066 struct netagent_registration *existing_registration = netagent_find_agent_with_uuid_and_lock(new_registration->netagent->netagent_uuid, false, true);
1067 if (existing_registration != NULL) {
1068 NETAGENTLOG0(LOG_ERR, "Existing agent registration UUID conflicts with new agent registration");
1069 // Don't fail the registration for now
1070 }
1071
1072 new_registration->control_unit = session->control_unit;
1073 new_registration->allow_multiple_registrations = session->allow_multiple_registrations;
1074 new_registration->event_handler = session->event_handler;
1075 new_registration->event_context = session->event_context;
1076 new_registration->generation = g_next_generation++;
1077
1078 TAILQ_INSERT_TAIL(&session->registrations, new_registration, session_chain);
1079 LIST_INSERT_HEAD(&shared_netagent_list, new_registration, global_chain);
1080 TAILQ_INIT(&new_registration->token_list);
1081 LIST_INIT(&new_registration->pending_triggers_list);
1082
1083 new_registration->netagent->netagent_flags |= NETAGENT_FLAG_REGISTERED;
1084 netagent_registered_count++;
1085 if (new_registration->netagent->netagent_flags & NETAGENT_FLAG_ACTIVE) {
1086 netagent_active_count++;
1087 }
1088
1089 NETAGENT_SESSION_UNLOCK(session);
1090 NETAGENT_LIST_UNLOCK();
1091 return 0;
1092 }
1093
1094 errno_t
netagent_register(netagent_session_t _session,struct netagent * agent)1095 netagent_register(netagent_session_t _session, struct netagent *agent)
1096 {
1097 struct netagent_registration *new_registration = NULL;
1098 uuid_t registered_uuid;
1099
1100 struct netagent_session *session = (struct netagent_session *)_session;
1101 if (session == NULL) {
1102 NETAGENTLOG0(LOG_ERR, "Cannot register agent on NULL session");
1103 return EINVAL;
1104 }
1105
1106 if (agent == NULL) {
1107 NETAGENTLOG0(LOG_ERR, "Cannot register NULL agent");
1108 return EINVAL;
1109 }
1110
1111 size_t data_size = agent->netagent_data_size;
1112 if (data_size > NETAGENT_MAX_DATA_SIZE) {
1113 NETAGENTLOG(LOG_ERR, "Register message size could not be read, data_size %zu",
1114 data_size);
1115 return EINVAL;
1116 }
1117
1118 new_registration = netagent_alloc_registration_memory(data_size);
1119
1120 __nochk_memcpy(new_registration->netagent, agent, sizeof(struct netagent));
1121 __nochk_memcpy(netagent_get_data(new_registration->netagent), netagent_get_data(agent), data_size);
1122
1123 uuid_copy(registered_uuid, new_registration->netagent->netagent_uuid);
1124
1125 errno_t error = netagent_handle_register_inner(session, new_registration);
1126 if (error != 0) {
1127 netagent_free_registration_memory(new_registration);
1128 return error;
1129 }
1130
1131 NETAGENTLOG0(LOG_DEBUG, "Registered new agent");
1132 netagent_post_event(registered_uuid, KEV_NETAGENT_REGISTERED, TRUE, false);
1133
1134 return 0;
1135 }
1136
1137 static errno_t
netagent_handle_register_setopt(struct netagent_session * session,u_int8_t * payload,size_t payload_length)1138 netagent_handle_register_setopt(struct netagent_session *session, u_int8_t *payload,
1139 size_t payload_length)
1140 {
1141 struct netagent_registration *new_registration = NULL;
1142 errno_t response_error = 0;
1143 struct netagent *register_netagent = (struct netagent *)(void *)payload;
1144 uuid_t registered_uuid;
1145
1146 if (session == NULL) {
1147 NETAGENTLOG0(LOG_ERR, "Failed to find session");
1148 response_error = EINVAL;
1149 goto done;
1150 }
1151
1152 if (payload == NULL) {
1153 NETAGENTLOG0(LOG_ERR, "No payload received");
1154 response_error = EINVAL;
1155 goto done;
1156 }
1157
1158 if (payload_length < sizeof(struct netagent)) {
1159 NETAGENTLOG(LOG_ERR, "Register message size too small for agent: (%zu < %zu)",
1160 payload_length, sizeof(struct netagent));
1161 response_error = EINVAL;
1162 goto done;
1163 }
1164
1165 size_t data_size = register_netagent->netagent_data_size;
1166 if (data_size > NETAGENT_MAX_DATA_SIZE) {
1167 NETAGENTLOG(LOG_ERR, "Register message size could not be read, data_size %zu", data_size);
1168 response_error = EINVAL;
1169 goto done;
1170 }
1171
1172 if (payload_length != (sizeof(struct netagent) + data_size)) {
1173 NETAGENTLOG(LOG_ERR, "Mismatch between data size and payload length (%lu != %zu)", (sizeof(struct netagent) + data_size), payload_length);
1174 response_error = EINVAL;
1175 goto done;
1176 }
1177
1178 new_registration = netagent_alloc_registration_memory(data_size);
1179
1180 __nochk_memcpy(new_registration->netagent, register_netagent, sizeof(struct netagent));
1181 __nochk_memcpy(netagent_get_data(new_registration->netagent), netagent_get_data(register_netagent), data_size);
1182
1183 uuid_copy(registered_uuid, new_registration->netagent->netagent_uuid);
1184
1185 response_error = netagent_handle_register_inner(session, new_registration);
1186 if (response_error != 0) {
1187 netagent_free_registration_memory(new_registration);
1188 goto done;
1189 }
1190
1191 NETAGENTLOG0(LOG_DEBUG, "Registered new agent");
1192 netagent_post_event(registered_uuid, KEV_NETAGENT_REGISTERED, TRUE, false);
1193
1194 done:
1195 return response_error;
1196 }
1197
1198 static void
netagent_handle_register_message(struct netagent_session * session,u_int32_t message_id,size_t payload_length,mbuf_t packet,size_t offset)1199 netagent_handle_register_message(struct netagent_session *session, u_int32_t message_id,
1200 size_t payload_length, mbuf_t packet, size_t offset)
1201 {
1202 errno_t error;
1203 struct netagent_registration *new_registration = NULL;
1204 u_int32_t response_error = NETAGENT_MESSAGE_ERROR_INTERNAL;
1205 uuid_t registered_uuid;
1206
1207 if (session == NULL) {
1208 NETAGENTLOG0(LOG_ERR, "Failed to find session");
1209 response_error = NETAGENT_MESSAGE_ERROR_INTERNAL;
1210 goto fail;
1211 }
1212
1213 if (session->allow_multiple_registrations) {
1214 NETAGENTLOG0(LOG_ERR, "Not allowed to register multiple agents");
1215 response_error = NETAGENT_MESSAGE_ERROR_INVALID_DATA;
1216 goto fail;
1217 }
1218
1219 if (payload_length < sizeof(struct netagent)) {
1220 NETAGENTLOG(LOG_ERR, "Register message size too small for agent: (%zu < %zu)",
1221 payload_length, sizeof(struct netagent));
1222 response_error = NETAGENT_MESSAGE_ERROR_INVALID_DATA;
1223 goto fail;
1224 }
1225
1226 size_t data_size = netagent_packet_get_netagent_data_size(packet, offset, &error);
1227 if (error || data_size > NETAGENT_MAX_DATA_SIZE) {
1228 NETAGENTLOG(LOG_ERR, "Register message size could not be read, error %d data_size %zu",
1229 error, data_size);
1230 response_error = NETAGENT_MESSAGE_ERROR_INVALID_DATA;
1231 goto fail;
1232 }
1233
1234 new_registration = netagent_alloc_registration_memory(data_size);
1235
1236 error = mbuf_copydata(packet, offset, sizeof(struct netagent) + data_size,
1237 new_registration->netagent);
1238 if (error) {
1239 NETAGENTLOG(LOG_ERR, "Failed to read data into agent structure: %d", error);
1240 netagent_free_registration_memory(new_registration);
1241 response_error = NETAGENT_MESSAGE_ERROR_INTERNAL;
1242 goto fail;
1243 }
1244
1245 uuid_copy(registered_uuid, new_registration->netagent->netagent_uuid);
1246
1247 error = netagent_handle_register_inner(session, new_registration);
1248 if (error) {
1249 NETAGENTLOG(LOG_ERR, "Failed to register agent: %d", error);
1250 netagent_free_registration_memory(new_registration);
1251 response_error = NETAGENT_MESSAGE_ERROR_INTERNAL;
1252 goto fail;
1253 }
1254
1255 NETAGENTLOG0(LOG_DEBUG, "Registered new agent");
1256 netagent_send_success_response(session, NETAGENT_MESSAGE_TYPE_REGISTER, message_id);
1257 netagent_post_event(registered_uuid, KEV_NETAGENT_REGISTERED, TRUE, false);
1258 return;
1259 fail:
1260 netagent_send_error_response(session, NETAGENT_MESSAGE_TYPE_REGISTER, message_id, response_error);
1261 }
1262
1263 errno_t
netagent_unregister(netagent_session_t _session)1264 netagent_unregister(netagent_session_t _session)
1265 {
1266 struct netagent_session *session = (struct netagent_session *)_session;
1267 if (session == NULL) {
1268 NETAGENTLOG0(LOG_ERR, "Cannot unregister NULL session");
1269 return EINVAL;
1270 }
1271
1272 netagent_unregister_all_session_registrations(session);
1273 return 0;
1274 }
1275
1276 static errno_t
netagent_handle_unregister_setopt(struct netagent_session * session,u_int8_t * __sized_by (payload_length)payload,size_t payload_length)1277 netagent_handle_unregister_setopt(struct netagent_session *session, u_int8_t * __sized_by(payload_length) payload,
1278 size_t payload_length)
1279 {
1280 errno_t response_error = 0;
1281
1282 if (session == NULL) {
1283 NETAGENTLOG0(LOG_ERR, "Failed to find session");
1284 response_error = EINVAL;
1285 goto done;
1286 }
1287
1288 if (!session->allow_multiple_registrations) {
1289 netagent_unregister_all_session_registrations(session);
1290 } else {
1291 if (payload == NULL) {
1292 NETAGENTLOG0(LOG_ERR, "No payload received");
1293 response_error = EINVAL;
1294 goto done;
1295 }
1296
1297 if (payload_length < sizeof(uuid_t)) {
1298 NETAGENTLOG(LOG_ERR, "Unregister message size too small for UUID: (%zu < %zu)",
1299 payload_length, sizeof(uuid_t));
1300 response_error = EINVAL;
1301 goto done;
1302 }
1303
1304 uuid_t agent_uuid = {};
1305 uuid_copy(agent_uuid, payload);
1306 netagent_unregister_one_session_registration(session, agent_uuid);
1307 }
1308
1309 done:
1310 return response_error;
1311 }
1312
1313 static errno_t
netagent_handle_unregister_all_setopt(struct netagent_session * session,u_int8_t * __sized_by (payload_length)payload,size_t payload_length)1314 netagent_handle_unregister_all_setopt(struct netagent_session *session, u_int8_t * __sized_by(payload_length) payload,
1315 size_t payload_length)
1316 {
1317 #pragma unused(payload, payload_length)
1318
1319 errno_t response_error = 0;
1320
1321 if (session == NULL) {
1322 NETAGENTLOG0(LOG_ERR, "Failed to find session");
1323 response_error = EINVAL;
1324 goto done;
1325 }
1326
1327 netagent_unregister_all_session_registrations(session);
1328
1329 done:
1330 return response_error;
1331 }
1332
1333 static void
netagent_handle_unregister_message(struct netagent_session * session,u_int32_t message_id,size_t payload_length,mbuf_t packet,size_t offset)1334 netagent_handle_unregister_message(struct netagent_session *session, u_int32_t message_id,
1335 size_t payload_length, mbuf_t packet, size_t offset)
1336 {
1337 #pragma unused(payload_length, packet, offset)
1338 u_int32_t response_error = NETAGENT_MESSAGE_ERROR_INTERNAL;
1339
1340 if (session == NULL) {
1341 NETAGENTLOG0(LOG_ERR, "Failed to find session");
1342 response_error = NETAGENT_MESSAGE_ERROR_INTERNAL;
1343 goto fail;
1344 }
1345
1346 if (session->allow_multiple_registrations) {
1347 NETAGENTLOG0(LOG_ERR, "Not allowed to register multiple agents");
1348 response_error = NETAGENT_MESSAGE_ERROR_INVALID_DATA;
1349 goto fail;
1350 }
1351
1352 netagent_unregister_all_session_registrations(session);
1353
1354 netagent_send_success_response(session, NETAGENT_MESSAGE_TYPE_UNREGISTER, message_id);
1355 return;
1356 fail:
1357 netagent_send_error_response(session, NETAGENT_MESSAGE_TYPE_UNREGISTER, message_id, response_error);
1358 }
1359
1360 static void
netagent_send_cellular_failed_event(struct netagent_registration * registration,pid_t pid,uuid_t proc_uuid)1361 netagent_send_cellular_failed_event(struct netagent_registration *registration,
1362 pid_t pid, uuid_t proc_uuid)
1363 {
1364 if (strlcmp(registration->netagent->netagent_domain, "Cellular", NETAGENT_DOMAINSIZE) != 0) {
1365 return;
1366 }
1367
1368 struct kev_netpolicy_ifdenied ev_ifdenied;
1369
1370 bzero(&ev_ifdenied, sizeof(ev_ifdenied));
1371
1372 ev_ifdenied.ev_data.epid = (u_int64_t)pid;
1373 uuid_copy(ev_ifdenied.ev_data.euuid, proc_uuid);
1374 ev_ifdenied.ev_if_functional_type = IFRTYPE_FUNCTIONAL_CELLULAR;
1375
1376 netpolicy_post_msg(KEV_NETPOLICY_IFFAILED, &ev_ifdenied.ev_data, sizeof(ev_ifdenied));
1377 }
1378
1379 static errno_t
netagent_handle_update_inner(struct netagent_session * session,struct netagent_registration * new_registration,size_t data_size,u_int8_t * agent_changed,netagent_error_domain_t error_domain)1380 netagent_handle_update_inner(struct netagent_session *session, struct netagent_registration *new_registration,
1381 size_t data_size, u_int8_t *agent_changed, netagent_error_domain_t error_domain)
1382 {
1383 errno_t response_error = 0;
1384
1385 if (agent_changed == NULL) {
1386 NETAGENTLOG0(LOG_ERR, "Invalid argument: agent_changed");
1387 return EINVAL;
1388 }
1389
1390 NETAGENT_LIST_LOCK_EXCLUSIVE();
1391
1392 NETAGENT_SESSION_LOCK(session);
1393 struct netagent_registration *registration = NULL;
1394 if (session->allow_multiple_registrations) {
1395 registration = netagent_session_find_agent_with_uuid_and_lock(session, new_registration->netagent->netagent_uuid, true, false);
1396 } else {
1397 registration = netagent_session_access_agent_with_lock(session, true, false);
1398 }
1399
1400 if (registration == NULL) {
1401 NETAGENT_SESSION_UNLOCK(session);
1402 NETAGENT_LIST_UNLOCK();
1403 response_error = ENOENT;
1404 return response_error;
1405 }
1406
1407 if (uuid_compare(registration->netagent->netagent_uuid, new_registration->netagent->netagent_uuid) != 0 ||
1408 memcmp(®istration->netagent->netagent_domain, &new_registration->netagent->netagent_domain,
1409 sizeof(new_registration->netagent->netagent_domain)) != 0 ||
1410 memcmp(®istration->netagent->netagent_type, &new_registration->netagent->netagent_type,
1411 sizeof(new_registration->netagent->netagent_type)) != 0) {
1412 NETAGENT_UNLOCK(registration);
1413 NETAGENT_SESSION_UNLOCK(session);
1414 NETAGENT_LIST_UNLOCK();
1415 NETAGENTLOG0(LOG_ERR, "Basic agent parameters do not match, cannot update");
1416 if (error_domain == kNetagentErrorDomainPOSIX) {
1417 response_error = EINVAL;
1418 } else if (error_domain == kNetagentErrorDomainUserDefined) {
1419 response_error = NETAGENT_MESSAGE_ERROR_CANNOT_UPDATE;
1420 }
1421 return response_error;
1422 }
1423
1424 new_registration->netagent->netagent_flags |= NETAGENT_FLAG_REGISTERED;
1425 if (registration->netagent->netagent_data_size == new_registration->netagent->netagent_data_size &&
1426 memcmp(registration->netagent, new_registration->netagent, sizeof(struct netagent)) == 0 &&
1427 memcmp(netagent_get_data(registration->netagent), netagent_get_data(new_registration->netagent), data_size) == 0) {
1428 // Agent is exactly identical, don't increment the generation count
1429
1430 // Make a copy of the list of pending clients, and clear the current list
1431 struct netagent_client_list_s pending_triggers_list_copy;
1432 LIST_INIT(&pending_triggers_list_copy);
1433 struct netagent_client * __single search_client = NULL;
1434 struct netagent_client *temp_client = NULL;
1435 LIST_FOREACH_SAFE(search_client, ®istration->pending_triggers_list, client_chain, temp_client) {
1436 LIST_REMOVE(search_client, client_chain);
1437 LIST_INSERT_HEAD(&pending_triggers_list_copy, search_client, client_chain);
1438 }
1439 NETAGENT_UNLOCK(registration);
1440 NETAGENT_SESSION_UNLOCK(session);
1441 NETAGENT_LIST_UNLOCK();
1442
1443 // Update pending client triggers without holding a lock
1444 search_client = NULL;
1445 temp_client = NULL;
1446 LIST_FOREACH_SAFE(search_client, &pending_triggers_list_copy, client_chain, temp_client) {
1447 necp_force_update_client(search_client->client_id, registration->netagent->netagent_uuid, registration->generation);
1448 netagent_send_cellular_failed_event(new_registration, search_client->client_pid, search_client->client_proc_uuid);
1449 LIST_REMOVE(search_client, client_chain);
1450 kfree_type(struct netagent_client, search_client);
1451 }
1452 NETAGENTLOG0(LOG_DEBUG, "Updated agent (no changes)");
1453 *agent_changed = FALSE;
1454 return response_error;
1455 }
1456
1457 new_registration->generation = g_next_generation++;
1458 new_registration->use_count = registration->use_count;
1459
1460 TAILQ_INIT(&new_registration->token_list);
1461 TAILQ_CONCAT(&new_registration->token_list, ®istration->token_list, token_chain);
1462 new_registration->token_count = registration->token_count;
1463 new_registration->token_low_water = registration->token_low_water;
1464 new_registration->last_client_error = registration->last_client_error;
1465 new_registration->client_error_count = registration->client_error_count;
1466 new_registration->allow_multiple_registrations = registration->allow_multiple_registrations;
1467
1468 if ((new_registration->netagent->netagent_flags & NETAGENT_FLAG_ACTIVE) &&
1469 !(registration->netagent->netagent_flags & NETAGENT_FLAG_ACTIVE)) {
1470 netagent_active_count++;
1471 } else if (!(new_registration->netagent->netagent_flags & NETAGENT_FLAG_ACTIVE) &&
1472 (registration->netagent->netagent_flags & NETAGENT_FLAG_ACTIVE) &&
1473 netagent_active_count > 0) {
1474 netagent_active_count--;
1475 }
1476
1477 TAILQ_REMOVE(&session->registrations, registration, session_chain);
1478 LIST_REMOVE(registration, global_chain);
1479 NETAGENT_UNLOCK(registration);
1480 netagent_free_registration(registration);
1481 TAILQ_INSERT_TAIL(&session->registrations, new_registration, session_chain);
1482 new_registration->control_unit = session->control_unit;
1483 new_registration->event_handler = session->event_handler;
1484 new_registration->event_context = session->event_context;
1485 LIST_INSERT_HEAD(&shared_netagent_list, new_registration, global_chain);
1486 LIST_INIT(&new_registration->pending_triggers_list);
1487
1488 NETAGENT_SESSION_UNLOCK(session);
1489 NETAGENT_LIST_UNLOCK();
1490
1491 NETAGENTLOG0(LOG_DEBUG, "Updated agent");
1492 *agent_changed = TRUE;
1493
1494 return response_error;
1495 }
1496
1497 errno_t
netagent_update(netagent_session_t _session,struct netagent * agent)1498 netagent_update(netagent_session_t _session, struct netagent *agent)
1499 {
1500 u_int8_t agent_changed;
1501 struct netagent_registration *new_registration = NULL;
1502 bool should_update_immediately;
1503 uuid_t updated_uuid;
1504
1505 struct netagent_session *session = (struct netagent_session *)_session;
1506 if (session == NULL) {
1507 NETAGENTLOG0(LOG_ERR, "Cannot update agent on NULL session");
1508 return EINVAL;
1509 }
1510
1511 if (agent == NULL) {
1512 NETAGENTLOG0(LOG_ERR, "Cannot register NULL agent");
1513 return EINVAL;
1514 }
1515
1516 size_t data_size = agent->netagent_data_size;
1517 if (data_size > NETAGENT_MAX_DATA_SIZE) {
1518 NETAGENTLOG(LOG_ERR, "Update message size (%zu > %u) too large", data_size, NETAGENT_MAX_DATA_SIZE);
1519 return EINVAL;
1520 }
1521
1522 new_registration = netagent_alloc_registration_memory(data_size);
1523
1524 __nochk_memcpy(new_registration->netagent, agent, sizeof(struct netagent));
1525 __nochk_memcpy(netagent_get_data(new_registration->netagent), netagent_get_data(agent), data_size);
1526
1527 uuid_copy(updated_uuid, new_registration->netagent->netagent_uuid);
1528 should_update_immediately = (NETAGENT_FLAG_UPDATE_IMMEDIATELY == (new_registration->netagent->netagent_flags & NETAGENT_FLAG_UPDATE_IMMEDIATELY));
1529
1530 errno_t error = netagent_handle_update_inner(session, new_registration, data_size, &agent_changed, kNetagentErrorDomainPOSIX);
1531 if (error == 0) {
1532 netagent_post_event(updated_uuid, KEV_NETAGENT_UPDATED, agent_changed, should_update_immediately);
1533 if (agent_changed == FALSE) {
1534 // The session registration does not need the "new_registration" as nothing changed
1535 netagent_free_registration_memory(new_registration);
1536 }
1537 } else {
1538 netagent_free_registration_memory(new_registration);
1539 return error;
1540 }
1541
1542 return 0;
1543 }
1544
1545 static errno_t
netagent_handle_update_setopt(struct netagent_session * session,u_int8_t * payload,size_t payload_length)1546 netagent_handle_update_setopt(struct netagent_session *session, u_int8_t *payload, size_t payload_length)
1547 {
1548 struct netagent_registration *new_registration = NULL;
1549 errno_t response_error = 0;
1550 struct netagent *update_netagent = (struct netagent *)(void *)payload;
1551 u_int8_t agent_changed;
1552 bool should_update_immediately;
1553 uuid_t updated_uuid;
1554
1555 if (session == NULL) {
1556 NETAGENTLOG0(LOG_ERR, "Failed to find session");
1557 response_error = EINVAL;
1558 goto done;
1559 }
1560
1561 if (payload == NULL) {
1562 NETAGENTLOG0(LOG_ERR, "No payload received");
1563 response_error = EINVAL;
1564 goto done;
1565 }
1566
1567 if (payload_length < sizeof(struct netagent)) {
1568 NETAGENTLOG(LOG_ERR, "Update message size too small for agent: (%zu < %zu)",
1569 payload_length, sizeof(struct netagent));
1570 response_error = EINVAL;
1571 goto done;
1572 }
1573
1574 size_t data_size = update_netagent->netagent_data_size;
1575 if (data_size > NETAGENT_MAX_DATA_SIZE) {
1576 NETAGENTLOG(LOG_ERR, "Update message size (%zu > %u) too large", data_size, NETAGENT_MAX_DATA_SIZE);
1577 response_error = EINVAL;
1578 goto done;
1579 }
1580
1581 if (payload_length != (sizeof(struct netagent) + data_size)) {
1582 NETAGENTLOG(LOG_ERR, "Mismatch between data size and payload length (%lu != %zu)", (sizeof(struct netagent) + data_size), payload_length);
1583 response_error = EINVAL;
1584 goto done;
1585 }
1586
1587 new_registration = netagent_alloc_registration_memory(data_size);
1588
1589 __nochk_memcpy(new_registration->netagent, update_netagent, sizeof(struct netagent));
1590 __nochk_memcpy(netagent_get_data(new_registration->netagent), netagent_get_data(update_netagent), data_size);
1591
1592 uuid_copy(updated_uuid, new_registration->netagent->netagent_uuid);
1593 should_update_immediately = (NETAGENT_FLAG_UPDATE_IMMEDIATELY == (new_registration->netagent->netagent_flags & NETAGENT_FLAG_UPDATE_IMMEDIATELY));
1594
1595 response_error = netagent_handle_update_inner(session, new_registration, data_size, &agent_changed, kNetagentErrorDomainPOSIX);
1596 if (response_error == 0) {
1597 netagent_post_event(updated_uuid, KEV_NETAGENT_UPDATED, agent_changed, should_update_immediately);
1598 if (agent_changed == FALSE) {
1599 // The session registration does not need the "new_registration" as nothing changed
1600 netagent_free_registration_memory(new_registration);
1601 }
1602 } else {
1603 netagent_free_registration_memory(new_registration);
1604 }
1605
1606 done:
1607 return response_error;
1608 }
1609
1610 static void
netagent_handle_update_message(struct netagent_session * session,u_int32_t message_id,size_t payload_length,mbuf_t packet,size_t offset)1611 netagent_handle_update_message(struct netagent_session *session, u_int32_t message_id,
1612 size_t payload_length, mbuf_t packet, size_t offset)
1613 {
1614 int error;
1615 struct netagent_registration *new_registration = NULL;
1616 u_int32_t response_error = NETAGENT_MESSAGE_ERROR_INTERNAL;
1617 u_int8_t agent_changed;
1618 uuid_t updated_uuid;
1619 bool should_update_immediately;
1620
1621 if (session == NULL) {
1622 NETAGENTLOG0(LOG_ERR, "Failed to find session");
1623 response_error = NETAGENT_MESSAGE_ERROR_INTERNAL;
1624 goto fail;
1625 }
1626
1627 if (payload_length < sizeof(struct netagent)) {
1628 NETAGENTLOG(LOG_ERR, "Update message size too small for agent: (%zu < %zu)",
1629 payload_length, sizeof(struct netagent));
1630 response_error = NETAGENT_MESSAGE_ERROR_INVALID_DATA;
1631 goto fail;
1632 }
1633
1634 size_t data_size = netagent_packet_get_netagent_data_size(packet, offset, &error);
1635 if (error || data_size > NETAGENT_MAX_DATA_SIZE) {
1636 NETAGENTLOG(LOG_ERR, "Update message size could not be read, error %d data_size %zu",
1637 error, data_size);
1638 response_error = NETAGENT_MESSAGE_ERROR_INVALID_DATA;
1639 goto fail;
1640 }
1641
1642 new_registration = netagent_alloc_registration_memory(data_size);
1643
1644 error = mbuf_copydata(packet, offset, new_registration->netagent_alloc_size, new_registration->netagent);
1645 if (error) {
1646 NETAGENTLOG(LOG_ERR, "Failed to read data into agent structure: %d", error);
1647 netagent_free_registration_memory(new_registration);
1648 response_error = NETAGENT_MESSAGE_ERROR_INTERNAL;
1649 goto fail;
1650 }
1651
1652 uuid_copy(updated_uuid, new_registration->netagent->netagent_uuid);
1653 should_update_immediately = (NETAGENT_FLAG_UPDATE_IMMEDIATELY == (new_registration->netagent->netagent_flags & NETAGENT_FLAG_UPDATE_IMMEDIATELY));
1654
1655 response_error = (u_int32_t)netagent_handle_update_inner(session, new_registration, data_size, &agent_changed, kNetagentErrorDomainUserDefined);
1656 if (response_error != 0) {
1657 if (response_error == ENOENT) {
1658 response_error = NETAGENT_MESSAGE_ERROR_NOT_REGISTERED;
1659 }
1660 netagent_free_registration_memory(new_registration);
1661 goto fail;
1662 }
1663
1664 netagent_send_success_response(session, NETAGENT_MESSAGE_TYPE_UPDATE, message_id);
1665
1666 netagent_post_event(updated_uuid, KEV_NETAGENT_UPDATED, agent_changed, should_update_immediately);
1667
1668 if (agent_changed == FALSE) {
1669 // The session registration does not need the "new_registration" as nothing changed
1670 netagent_free_registration_memory(new_registration);
1671 }
1672
1673 return;
1674 fail:
1675 netagent_send_error_response(session, NETAGENT_MESSAGE_TYPE_UPDATE, message_id, response_error);
1676 }
1677
1678 errno_t
netagent_assign_nexus(netagent_session_t _session,uuid_t necp_client_uuid,void * __sized_by (assigned_results_length)assign_message,size_t assigned_results_length)1679 netagent_assign_nexus(netagent_session_t _session, uuid_t necp_client_uuid,
1680 void * __sized_by(assigned_results_length)assign_message, size_t assigned_results_length)
1681 {
1682 struct netagent_session *session = (struct netagent_session *)_session;
1683 uuid_t netagent_uuid;
1684 if (session == NULL) {
1685 NETAGENTLOG0(LOG_ERR, "Cannot assign nexus from NULL session");
1686 return EINVAL;
1687 }
1688
1689 NETAGENT_SESSION_LOCK(session);
1690
1691 struct netagent_registration *registration = netagent_session_access_agent_with_lock(session, false, false);
1692 if (registration == NULL) {
1693 NETAGENT_SESSION_UNLOCK(session);
1694 NETAGENTLOG0(LOG_ERR, "Session has no matching agent");
1695 return ENOENT;
1696 }
1697 uuid_copy(netagent_uuid, registration->netagent->netagent_uuid);
1698 NETAGENT_UNLOCK(registration);
1699 NETAGENT_SESSION_UNLOCK(session);
1700
1701 // Note that if the error is 0, NECP has taken over our malloc'ed buffer
1702 int error = necp_assign_client_result(netagent_uuid, necp_client_uuid, assign_message, assigned_results_length);
1703 if (error) {
1704 // necp_assign_client_result returns POSIX errors; don't error for ENOENT
1705 NETAGENTLOG((error == ENOENT ? LOG_DEBUG : LOG_ERR), "Client assignment failed: %d", error);
1706 return error;
1707 }
1708
1709 NETAGENTLOG0(LOG_DEBUG, "Agent assigned nexus properties to client");
1710 return 0;
1711 }
1712
1713 errno_t
netagent_update_flow_protoctl_event(netagent_session_t _session,uuid_t client_id,uint32_t protoctl_event_code,uint32_t protoctl_event_val,uint32_t protoctl_event_tcp_seq_number)1714 netagent_update_flow_protoctl_event(netagent_session_t _session,
1715 uuid_t client_id, uint32_t protoctl_event_code,
1716 uint32_t protoctl_event_val, uint32_t protoctl_event_tcp_seq_number)
1717 {
1718 struct netagent_session *session = (struct netagent_session *)_session;
1719 uuid_t netagent_uuid;
1720 int error = 0;
1721
1722 if (session == NULL) {
1723 NETAGENTLOG0(LOG_ERR, "Cannot assign nexus from NULL session");
1724 return EINVAL;
1725 }
1726
1727 NETAGENT_SESSION_LOCK(session);
1728 struct netagent_registration *registration = netagent_session_access_agent_with_lock(session, false, false);
1729 if (registration == NULL) {
1730 NETAGENT_SESSION_UNLOCK(session);
1731 NETAGENTLOG0(LOG_ERR, "Session has no agent");
1732 return ENOENT;
1733 }
1734 uuid_copy(netagent_uuid, registration->netagent->netagent_uuid);
1735 NETAGENT_UNLOCK(registration);
1736 NETAGENT_SESSION_UNLOCK(session);
1737
1738 error = necp_update_flow_protoctl_event(netagent_uuid,
1739 client_id, protoctl_event_code, protoctl_event_val, protoctl_event_tcp_seq_number);
1740
1741 return error;
1742 }
1743
1744 static errno_t
netagent_handle_assign_nexus_setopt(struct netagent_session * session,u_int8_t * __sized_by (payload_length)payload,size_t payload_length)1745 netagent_handle_assign_nexus_setopt(struct netagent_session *session, u_int8_t * __sized_by(payload_length)payload,
1746 size_t payload_length)
1747 {
1748 errno_t response_error = 0;
1749 uuid_t client_id;
1750 uuid_t netagent_uuid;
1751 u_int8_t *assigned_results = NULL;
1752
1753 if (session == NULL) {
1754 NETAGENTLOG0(LOG_ERR, "Failed to find session");
1755 response_error = ENOENT;
1756 goto done;
1757 }
1758
1759 if (payload == NULL) {
1760 NETAGENTLOG0(LOG_ERR, "No payload received");
1761 response_error = EINVAL;
1762 goto done;
1763 }
1764
1765 NETAGENT_SESSION_LOCK(session);
1766
1767 const size_t header_offset = (session->allow_multiple_registrations ? sizeof(uuid_t) : 0);
1768 if (payload_length < header_offset) {
1769 NETAGENT_SESSION_UNLOCK(session);
1770 NETAGENTLOG0(LOG_ERR, "Assign message is too short");
1771 response_error = EINVAL;
1772 goto done;
1773 }
1774
1775 struct netagent_assign_nexus_message * __single assign_nexus_netagent = (struct netagent_assign_nexus_message *)(void *)((u_int8_t *)payload + header_offset);
1776
1777 struct netagent_registration *registration = NULL;
1778 if (session->allow_multiple_registrations) {
1779 uuid_t agent_uuid = {};
1780 uuid_copy(agent_uuid, payload);
1781 registration = netagent_session_find_agent_with_uuid_and_lock(session, agent_uuid, false, false);
1782 } else {
1783 registration = netagent_session_access_agent_with_lock(session, false, false);
1784 }
1785
1786 if (registration == NULL) {
1787 NETAGENT_SESSION_UNLOCK(session);
1788 NETAGENTLOG0(LOG_ERR, "Session has no agent to get");
1789 response_error = ENOENT;
1790 goto done;
1791 }
1792
1793 uuid_copy(netagent_uuid, registration->netagent->netagent_uuid);
1794 NETAGENT_UNLOCK(registration);
1795 NETAGENT_SESSION_UNLOCK(session);
1796
1797 if (payload_length < (header_offset + sizeof(uuid_t))) {
1798 NETAGENTLOG0(LOG_ERR, "Assign message is too short");
1799 response_error = EINVAL;
1800 goto done;
1801 }
1802
1803 memcpy(client_id, assign_nexus_netagent->assign_client_id, sizeof(client_id));
1804 size_t assigned_results_length = (payload_length - (header_offset + sizeof(client_id)));
1805
1806 if (assigned_results_length > 0) {
1807 assigned_results = kalloc_data(assigned_results_length, Z_WAITOK);
1808 if (assigned_results == NULL) {
1809 NETAGENTLOG(LOG_ERR, "Failed to allocate assign message (%lu bytes)", assigned_results_length);
1810 response_error = ENOMEM;
1811 goto done;
1812 }
1813 memcpy(assigned_results,
1814 netagent_assign_message_get_necp_result(assign_nexus_netagent, assigned_results_length),
1815 assigned_results_length);
1816 }
1817
1818 // Note that if the error is 0, NECP has taken over our malloc'ed buffer
1819 response_error = necp_assign_client_result(netagent_uuid, client_id, assigned_results, assigned_results_length);
1820 if (response_error) {
1821 // necp_assign_client_result returns POSIX errors
1822 kfree_data(assigned_results, assigned_results_length);
1823 NETAGENTLOG(LOG_ERR, "Client assignment failed: %d", response_error);
1824 goto done;
1825 }
1826
1827 NETAGENTLOG0(LOG_DEBUG, "Agent assigned nexus properties to client");
1828 done:
1829 return response_error;
1830 }
1831
1832 static void
netagent_handle_assign_nexus_message(struct netagent_session * session,u_int32_t message_id,size_t payload_length,mbuf_t packet,size_t offset)1833 netagent_handle_assign_nexus_message(struct netagent_session *session, u_int32_t message_id,
1834 size_t payload_length, mbuf_t packet, size_t offset)
1835 {
1836 int error = 0;
1837 u_int32_t response_error = NETAGENT_MESSAGE_ERROR_INTERNAL;
1838 uuid_t client_id;
1839 uuid_t netagent_uuid;
1840 u_int8_t * assigned_results = NULL;
1841
1842 if (session == NULL) {
1843 NETAGENTLOG0(LOG_ERR, "Failed to find session");
1844 response_error = NETAGENT_MESSAGE_ERROR_INTERNAL;
1845 goto fail;
1846 }
1847
1848 NETAGENT_SESSION_LOCK(session);
1849 struct netagent_registration *registration = netagent_session_access_agent_with_lock(session, false, false);
1850 if (registration == NULL) {
1851 NETAGENT_SESSION_UNLOCK(session);
1852 NETAGENTLOG0(LOG_ERR, "Session has no agent to get");
1853 response_error = NETAGENT_MESSAGE_ERROR_NOT_REGISTERED;
1854 goto fail;
1855 }
1856 uuid_copy(netagent_uuid, registration->netagent->netagent_uuid);
1857 NETAGENT_UNLOCK(registration);
1858 NETAGENT_SESSION_UNLOCK(session);
1859
1860 if (payload_length < sizeof(uuid_t)) {
1861 NETAGENTLOG0(LOG_ERR, "Assign message is too short");
1862 response_error = NETAGENT_MESSAGE_ERROR_INVALID_DATA;
1863 goto fail;
1864 }
1865
1866 error = mbuf_copydata(packet, offset, sizeof(client_id), &client_id);
1867 if (error) {
1868 NETAGENTLOG(LOG_ERR, "Failed to read uuid for assign message: %d", error);
1869 response_error = NETAGENT_MESSAGE_ERROR_INTERNAL;
1870 goto fail;
1871 }
1872
1873 size_t assigned_results_length = (payload_length - sizeof(client_id));
1874 if (assigned_results_length > 0) {
1875 assigned_results = kalloc_data( assigned_results_length, Z_WAITOK);
1876 if (assigned_results == NULL) {
1877 NETAGENTLOG(LOG_ERR, "Failed to allocate assign message (%lu bytes)", assigned_results_length);
1878 response_error = NETAGENT_MESSAGE_ERROR_INTERNAL;
1879 goto fail;
1880 }
1881
1882 error = mbuf_copydata(packet, offset + sizeof(client_id), assigned_results_length, assigned_results);
1883 if (error) {
1884 kfree_data(assigned_results, assigned_results_length);
1885 NETAGENTLOG(LOG_ERR, "Failed to read assign message: %d", error);
1886 response_error = NETAGENT_MESSAGE_ERROR_INTERNAL;
1887 goto fail;
1888 }
1889 }
1890
1891 // Note that if the error is 0, NECP has taken over our malloc'ed buffer
1892 error = necp_assign_client_result(netagent_uuid, client_id, assigned_results, assigned_results_length);
1893 if (error) {
1894 kfree_data(assigned_results, assigned_results_length);
1895 NETAGENTLOG(LOG_ERR, "Client assignment failed: %d", error);
1896 response_error = NETAGENT_MESSAGE_ERROR_CANNOT_ASSIGN;
1897 goto fail;
1898 }
1899
1900 NETAGENTLOG0(LOG_DEBUG, "Agent assigned nexus properties to client");
1901 netagent_send_success_response(session, NETAGENT_MESSAGE_TYPE_ASSIGN_NEXUS, message_id);
1902 return;
1903 fail:
1904 netagent_send_error_response(session, NETAGENT_MESSAGE_TYPE_ASSIGN_NEXUS, message_id, response_error);
1905 }
1906
1907 static errno_t
netagent_handle_assign_group_setopt(struct netagent_session * session,u_int8_t * __sized_by (payload_length)payload,size_t payload_length)1908 netagent_handle_assign_group_setopt(struct netagent_session *session, u_int8_t * __sized_by(payload_length)payload,
1909 size_t payload_length)
1910 {
1911 errno_t response_error = 0;
1912 uuid_t client_id;
1913 uuid_t netagent_uuid;
1914 u_int8_t *assigned_group_members = NULL;
1915
1916 if (session == NULL) {
1917 NETAGENTLOG0(LOG_ERR, "Failed to find session");
1918 response_error = ENOENT;
1919 goto done;
1920 }
1921
1922 if (payload == NULL) {
1923 NETAGENTLOG0(LOG_ERR, "No payload received");
1924 response_error = EINVAL;
1925 goto done;
1926 }
1927
1928 NETAGENT_SESSION_LOCK(session);
1929
1930 const size_t header_offset = (session->allow_multiple_registrations ? sizeof(uuid_t) : 0);
1931 if (payload_length < header_offset) {
1932 NETAGENT_SESSION_UNLOCK(session);
1933 NETAGENTLOG0(LOG_ERR, "Assign message is too short");
1934 response_error = EINVAL;
1935 goto done;
1936 }
1937
1938 struct netagent_assign_nexus_message *assign_message = (struct netagent_assign_nexus_message *)(void *)((u_int8_t *)payload + header_offset);
1939
1940 struct netagent_registration *registration = NULL;
1941 if (session->allow_multiple_registrations) {
1942 uuid_t agent_uuid = {};
1943 uuid_copy(agent_uuid, payload);
1944 registration = netagent_session_find_agent_with_uuid_and_lock(session, agent_uuid, false, false);
1945 } else {
1946 registration = netagent_session_access_agent_with_lock(session, false, false);
1947 }
1948
1949 if (registration == NULL) {
1950 NETAGENT_SESSION_UNLOCK(session);
1951 NETAGENTLOG0(LOG_ERR, "Session has no agent to get");
1952 response_error = ENOENT;
1953 goto done;
1954 }
1955
1956 uuid_copy(netagent_uuid, registration->netagent->netagent_uuid);
1957 NETAGENT_UNLOCK(registration);
1958 NETAGENT_SESSION_UNLOCK(session);
1959
1960 if (payload_length < (header_offset + sizeof(uuid_t))) {
1961 NETAGENTLOG0(LOG_ERR, "Group assign message is too short");
1962 response_error = EINVAL;
1963 goto done;
1964 }
1965
1966 memcpy(client_id, assign_message->assign_client_id, sizeof(client_id));
1967 size_t assigned_group_members_length = (payload_length - (header_offset + sizeof(client_id)));
1968
1969 if (assigned_group_members_length > 0) {
1970 assigned_group_members = (u_int8_t *)kalloc_data(assigned_group_members_length, Z_WAITOK);
1971 if (assigned_group_members == NULL) {
1972 NETAGENTLOG(LOG_ERR, "Failed to allocate group assign message (%lu bytes)", assigned_group_members_length);
1973 response_error = ENOMEM;
1974 goto done;
1975 }
1976 memcpy(assigned_group_members, netagent_assign_message_get_necp_result(assign_message, assigned_group_members_length), assigned_group_members_length);
1977 }
1978
1979 // Note that if the error is 0, NECP has taken over our malloc'ed buffer
1980 response_error = necp_assign_client_group_members(netagent_uuid, client_id, assigned_group_members, assigned_group_members_length);
1981 if (response_error != 0) {
1982 // necp_assign_client_group_members returns POSIX errors
1983 if (assigned_group_members != NULL) {
1984 kfree_data(assigned_group_members, assigned_group_members_length);
1985 }
1986 NETAGENTLOG(LOG_ERR, "Client group assignment failed: %d", response_error);
1987 goto done;
1988 }
1989
1990 NETAGENTLOG0(LOG_DEBUG, "Agent assigned group members to client");
1991 done:
1992 return response_error;
1993 }
1994
1995 errno_t
netagent_handle_use_count_setopt(struct netagent_session * session,u_int8_t * __sized_by (payload_length)payload,size_t payload_length)1996 netagent_handle_use_count_setopt(struct netagent_session *session, u_int8_t * __sized_by(payload_length)payload, size_t payload_length)
1997 {
1998 errno_t response_error = 0;
1999 uint64_t use_count = 0;
2000
2001 if (session == NULL) {
2002 NETAGENTLOG0(LOG_ERR, "Failed to find session");
2003 response_error = ENOENT;
2004 goto done;
2005 }
2006
2007 if (payload == NULL) {
2008 NETAGENTLOG0(LOG_ERR, "No payload received");
2009 response_error = EINVAL;
2010 goto done;
2011 }
2012
2013 NETAGENT_SESSION_LOCK(session);
2014 const size_t header_offset = (session->allow_multiple_registrations ? sizeof(uuid_t) : 0);
2015 const size_t expected_length = header_offset + sizeof(use_count);
2016 if (payload_length != expected_length) {
2017 NETAGENT_SESSION_UNLOCK(session);
2018 NETAGENTLOG(LOG_ERR, "Payload length is invalid (%lu)", payload_length);
2019 response_error = EINVAL;
2020 goto done;
2021 }
2022
2023 memcpy(&use_count, payload + header_offset, sizeof(use_count));
2024
2025 struct netagent_registration *registration = NULL;
2026 if (session->allow_multiple_registrations) {
2027 uuid_t agent_uuid = {};
2028 uuid_copy(agent_uuid, payload);
2029 registration = netagent_session_find_agent_with_uuid_and_lock(session, agent_uuid, false, false);
2030 } else {
2031 registration = netagent_session_access_agent_with_lock(session, true, false);
2032 }
2033
2034 if (registration == NULL) {
2035 NETAGENT_SESSION_UNLOCK(session);
2036 NETAGENTLOG0(LOG_ERR, "Session has no agent registered");
2037 response_error = ENOENT;
2038 goto done;
2039 }
2040
2041 registration->use_count = use_count;
2042 NETAGENT_UNLOCK(registration);
2043 NETAGENT_SESSION_UNLOCK(session);
2044
2045 done:
2046 return response_error;
2047 }
2048
2049 errno_t
netagent_handle_use_count_getopt(struct netagent_session * session,u_int8_t * __sized_by (* buffer_length)buffer,size_t * buffer_length)2050 netagent_handle_use_count_getopt(struct netagent_session *session, u_int8_t * __sized_by(*buffer_length)buffer, size_t *buffer_length)
2051 {
2052 errno_t response_error = 0;
2053 uint64_t use_count = 0;
2054
2055 if (session == NULL) {
2056 NETAGENTLOG0(LOG_ERR, "Failed to find session");
2057 response_error = ENOENT;
2058 goto done;
2059 }
2060
2061 if (buffer == NULL) {
2062 NETAGENTLOG0(LOG_ERR, "No payload received");
2063 response_error = EINVAL;
2064 goto done;
2065 }
2066
2067 NETAGENT_SESSION_LOCK(session);
2068 const size_t header_offset = (session->allow_multiple_registrations ? sizeof(uuid_t) : 0);
2069 const size_t expected_length = header_offset + sizeof(use_count);
2070 if (*buffer_length != expected_length) {
2071 NETAGENT_SESSION_UNLOCK(session);
2072 NETAGENTLOG(LOG_ERR, "Buffer length is invalid (%lu)", *buffer_length);
2073 response_error = EINVAL;
2074 goto done;
2075 }
2076
2077 struct netagent_registration *registration = NULL;
2078 if (session->allow_multiple_registrations) {
2079 uuid_t agent_uuid = {};
2080 uuid_copy(agent_uuid, buffer);
2081 registration = netagent_session_find_agent_with_uuid_and_lock(session, agent_uuid, false, false);
2082 } else {
2083 registration = netagent_session_access_agent_with_lock(session, false, false);
2084 }
2085
2086 if (registration == NULL) {
2087 NETAGENT_SESSION_UNLOCK(session);
2088 NETAGENTLOG0(LOG_ERR, "Session has no agent registered");
2089 response_error = ENOENT;
2090 goto done;
2091 }
2092
2093 use_count = registration->use_count;
2094 NETAGENT_UNLOCK(registration);
2095 NETAGENT_SESSION_UNLOCK(session);
2096
2097 memcpy(buffer + header_offset, &use_count, sizeof(use_count));
2098 *buffer_length = (header_offset + sizeof(use_count));
2099
2100 done:
2101 return response_error;
2102 }
2103
2104 static errno_t
netagent_handle_add_token_setopt(struct netagent_session * session,u_int8_t * __sized_by (token_length)token,size_t token_length)2105 netagent_handle_add_token_setopt(struct netagent_session *session, u_int8_t * __sized_by(token_length)token, size_t token_length)
2106 {
2107 errno_t response_error = 0;
2108
2109 if (session == NULL) {
2110 NETAGENTLOG0(LOG_ERR, "Failed to find session");
2111 response_error = ENOENT;
2112 goto done;
2113 }
2114
2115 if (token == NULL) {
2116 NETAGENTLOG0(LOG_ERR, "No token received");
2117 response_error = EINVAL;
2118 goto done;
2119 }
2120
2121 NETAGENT_SESSION_LOCK(session);
2122 const size_t header_offset = (session->allow_multiple_registrations ? sizeof(uuid_t) : 0);
2123 if (token_length > (header_offset + NETAGENT_MAX_DATA_SIZE) ||
2124 token_length < header_offset) {
2125 NETAGENT_SESSION_UNLOCK(session);
2126 NETAGENTLOG(LOG_ERR, "Token length is invalid (%lu)", token_length);
2127 response_error = EINVAL;
2128 goto done;
2129 }
2130
2131 struct netagent_registration *registration = NULL;
2132 if (session->allow_multiple_registrations) {
2133 uuid_t agent_uuid = {};
2134 uuid_copy(agent_uuid, token);
2135 registration = netagent_session_find_agent_with_uuid_and_lock(session, agent_uuid, true, false);
2136 } else {
2137 registration = netagent_session_access_agent_with_lock(session, true, false);
2138 }
2139
2140 if (registration == NULL) {
2141 NETAGENT_SESSION_UNLOCK(session);
2142 NETAGENTLOG0(LOG_ERR, "Session has no agent registered");
2143 response_error = ENOENT;
2144 goto done;
2145 }
2146
2147 if (registration->token_count >= NETAGENT_MAX_TOKEN_COUNT) {
2148 NETAGENT_UNLOCK(registration);
2149 NETAGENT_SESSION_UNLOCK(session);
2150 NETAGENTLOG0(LOG_ERR, "Session cannot add more tokens");
2151 response_error = EINVAL;
2152 goto done;
2153 }
2154
2155 struct netagent_token *token_struct = NULL;
2156
2157 token_struct = kalloc_type(struct netagent_token, Z_WAITOK | Z_ZERO | Z_NOFAIL);
2158 token_struct->token_bytes = kalloc_data((token_length - header_offset), Z_WAITOK | Z_NOFAIL);
2159 token_struct->token_length = (u_int32_t)(token_length - header_offset);
2160 memcpy(token_struct->token_bytes, token + header_offset, (token_length - header_offset));
2161
2162 TAILQ_INSERT_TAIL(®istration->token_list, token_struct, token_chain);
2163
2164 registration->token_count++;
2165
2166 // Reset deadline time, now that there are more than 0 tokens
2167 registration->need_tokens_event_deadline = 0;
2168
2169 NETAGENT_UNLOCK(registration);
2170 NETAGENT_SESSION_UNLOCK(session);
2171 done:
2172 return response_error;
2173 }
2174
2175 static errno_t
netagent_handle_flush_tokens_setopt(struct netagent_session * session,u_int8_t * __sized_by (buffer_length)buffer,size_t buffer_length)2176 netagent_handle_flush_tokens_setopt(struct netagent_session *session, u_int8_t * __sized_by(buffer_length)buffer, size_t buffer_length)
2177 {
2178 errno_t response_error = 0;
2179
2180 if (session == NULL) {
2181 NETAGENTLOG0(LOG_ERR, "Failed to find session");
2182 response_error = ENOENT;
2183 goto done;
2184 }
2185
2186 NETAGENT_SESSION_LOCK(session);
2187 struct netagent_registration *registration = NULL;
2188 if (session->allow_multiple_registrations) {
2189 if (buffer_length != sizeof(uuid_t)) {
2190 NETAGENT_SESSION_UNLOCK(session);
2191 NETAGENTLOG(LOG_ERR, "Buffer length is invalid (%lu)", buffer_length);
2192 response_error = EINVAL;
2193 goto done;
2194 }
2195
2196 uuid_t agent_uuid = {};
2197 uuid_copy(agent_uuid, buffer);
2198 registration = netagent_session_find_agent_with_uuid_and_lock(session, agent_uuid, true, false);
2199 } else {
2200 registration = netagent_session_access_agent_with_lock(session, true, false);
2201 }
2202
2203 if (registration == NULL) {
2204 NETAGENT_SESSION_UNLOCK(session);
2205 NETAGENTLOG0(LOG_ERR, "Session has no agent registered");
2206 response_error = ENOENT;
2207 goto done;
2208 }
2209
2210 struct netagent_token *search_token = NULL;
2211 struct netagent_token *temp_token = NULL;
2212 TAILQ_FOREACH_SAFE(search_token, ®istration->token_list, token_chain, temp_token) {
2213 TAILQ_REMOVE(®istration->token_list, search_token, token_chain);
2214 netagent_token_free(search_token);
2215 }
2216 registration->token_count = 0;
2217 NETAGENT_UNLOCK(registration);
2218 NETAGENT_SESSION_UNLOCK(session);
2219 done:
2220 return response_error;
2221 }
2222
2223 static errno_t
netagent_handle_token_count_getopt(struct netagent_session * session,u_int8_t * __sized_by (* buffer_length)buffer,size_t * buffer_length)2224 netagent_handle_token_count_getopt(struct netagent_session *session, u_int8_t * __sized_by(*buffer_length)buffer, size_t *buffer_length)
2225 {
2226 errno_t response_error = 0;
2227 uint32_t token_count = 0;
2228
2229 if (session == NULL) {
2230 NETAGENTLOG0(LOG_ERR, "Failed to find session");
2231 response_error = ENOENT;
2232 goto done;
2233 }
2234
2235 if (buffer == NULL) {
2236 NETAGENTLOG0(LOG_ERR, "No payload received");
2237 response_error = EINVAL;
2238 goto done;
2239 }
2240
2241 NETAGENT_SESSION_LOCK(session);
2242 const size_t header_offset = (session->allow_multiple_registrations ? sizeof(uuid_t) : 0);
2243 const size_t expected_length = header_offset + sizeof(token_count);
2244 if (*buffer_length != expected_length) {
2245 NETAGENT_SESSION_UNLOCK(session);
2246 NETAGENTLOG(LOG_ERR, "Buffer length is invalid (%lu)", *buffer_length);
2247 response_error = EINVAL;
2248 goto done;
2249 }
2250
2251 struct netagent_registration *registration = NULL;
2252 if (session->allow_multiple_registrations) {
2253 uuid_t agent_uuid = {};
2254 uuid_copy(agent_uuid, buffer);
2255 registration = netagent_session_find_agent_with_uuid_and_lock(session, agent_uuid, false, false);
2256 } else {
2257 registration = netagent_session_access_agent_with_lock(session, false, false);
2258 }
2259
2260 if (registration == NULL) {
2261 NETAGENT_SESSION_UNLOCK(session);
2262 NETAGENTLOG0(LOG_ERR, "Session has no agent registered");
2263 response_error = ENOENT;
2264 goto done;
2265 }
2266
2267 token_count = registration->token_count;
2268 NETAGENT_UNLOCK(registration);
2269 NETAGENT_SESSION_UNLOCK(session);
2270
2271 memcpy(buffer + header_offset, &token_count, sizeof(token_count));
2272 *buffer_length = (header_offset + sizeof(token_count));
2273
2274 done:
2275 return response_error;
2276 }
2277
2278 static errno_t
netagent_handle_token_low_water_setopt(struct netagent_session * session,u_int8_t * __sized_by (buffer_length)buffer,size_t buffer_length)2279 netagent_handle_token_low_water_setopt(struct netagent_session *session, u_int8_t * __sized_by(buffer_length)buffer, size_t buffer_length)
2280 {
2281 errno_t response_error = 0;
2282 uint32_t token_low_water = 0;
2283
2284 if (session == NULL) {
2285 NETAGENTLOG0(LOG_ERR, "Failed to find session");
2286 response_error = ENOENT;
2287 goto done;
2288 }
2289
2290 if (buffer == NULL) {
2291 NETAGENTLOG0(LOG_ERR, "No payload received");
2292 response_error = EINVAL;
2293 goto done;
2294 }
2295
2296 NETAGENT_SESSION_LOCK(session);
2297 const size_t header_offset = (session->allow_multiple_registrations ? sizeof(uuid_t) : 0);
2298 const size_t expected_length = header_offset + sizeof(token_low_water);
2299 if (buffer_length != expected_length) {
2300 NETAGENT_SESSION_UNLOCK(session);
2301 NETAGENTLOG(LOG_ERR, "Buffer length is invalid (%lu)", buffer_length);
2302 response_error = EINVAL;
2303 goto done;
2304 }
2305
2306 memcpy(&token_low_water, buffer + header_offset, sizeof(token_low_water));
2307
2308 struct netagent_registration *registration = NULL;
2309 if (session->allow_multiple_registrations) {
2310 uuid_t agent_uuid = {};
2311 uuid_copy(agent_uuid, buffer);
2312 registration = netagent_session_find_agent_with_uuid_and_lock(session, agent_uuid, true, false);
2313 } else {
2314 registration = netagent_session_access_agent_with_lock(session, true, false);
2315 }
2316
2317 if (registration == NULL) {
2318 NETAGENT_SESSION_UNLOCK(session);
2319 NETAGENTLOG0(LOG_ERR, "Session has no agent registered");
2320 response_error = ENOENT;
2321 goto done;
2322 }
2323
2324 registration->token_low_water = token_low_water;
2325 NETAGENT_UNLOCK(registration);
2326 NETAGENT_SESSION_UNLOCK(session);
2327
2328 done:
2329 return response_error;
2330 }
2331
2332 static errno_t
netagent_handle_token_low_water_getopt(struct netagent_session * session,u_int8_t * __sized_by (* buffer_length)buffer,size_t * buffer_length)2333 netagent_handle_token_low_water_getopt(struct netagent_session *session, u_int8_t * __sized_by(*buffer_length)buffer, size_t *buffer_length)
2334 {
2335 errno_t response_error = 0;
2336 uint32_t token_low_water = 0;
2337
2338 if (session == NULL) {
2339 NETAGENTLOG0(LOG_ERR, "Failed to find session");
2340 response_error = ENOENT;
2341 goto done;
2342 }
2343
2344 if (buffer == NULL) {
2345 NETAGENTLOG0(LOG_ERR, "No payload received");
2346 response_error = EINVAL;
2347 goto done;
2348 }
2349
2350 NETAGENT_SESSION_LOCK(session);
2351 const size_t header_offset = (session->allow_multiple_registrations ? sizeof(uuid_t) : 0);
2352 const size_t expected_length = header_offset + sizeof(token_low_water);
2353 if (*buffer_length != expected_length) {
2354 NETAGENT_SESSION_UNLOCK(session);
2355 NETAGENTLOG(LOG_ERR, "Buffer length is invalid (%lu)", *buffer_length);
2356 response_error = EINVAL;
2357 goto done;
2358 }
2359
2360 struct netagent_registration *registration = NULL;
2361 if (session->allow_multiple_registrations) {
2362 uuid_t agent_uuid = {};
2363 uuid_copy(agent_uuid, buffer);
2364 registration = netagent_session_find_agent_with_uuid_and_lock(session, agent_uuid, false, false);
2365 } else {
2366 registration = netagent_session_access_agent_with_lock(session, false, false);
2367 }
2368
2369 if (registration == NULL) {
2370 NETAGENT_SESSION_UNLOCK(session);
2371 NETAGENTLOG0(LOG_ERR, "Session has no agent registered");
2372 response_error = ENOENT;
2373 goto done;
2374 }
2375
2376 token_low_water = registration->token_low_water;
2377 NETAGENT_UNLOCK(registration);
2378 NETAGENT_SESSION_UNLOCK(session);
2379
2380 memcpy(buffer + header_offset, &token_low_water, sizeof(token_low_water));
2381 *buffer_length = (header_offset + sizeof(token_low_water));
2382
2383 done:
2384 return response_error;
2385 }
2386
2387 static errno_t
netagent_handle_reset_client_error_setopt(struct netagent_session * session,u_int8_t * __sized_by (payload_length)payload,size_t payload_length)2388 netagent_handle_reset_client_error_setopt(struct netagent_session *session, u_int8_t * __sized_by(payload_length)payload, size_t payload_length)
2389 {
2390 errno_t response_error = 0;
2391
2392 if (session == NULL) {
2393 NETAGENTLOG0(LOG_ERR, "Failed to find session");
2394 response_error = ENOENT;
2395 goto done;
2396 }
2397
2398 NETAGENT_SESSION_LOCK(session);
2399 struct netagent_registration *registration = NULL;
2400 if (session->allow_multiple_registrations) {
2401 if (payload_length != sizeof(uuid_t)) {
2402 NETAGENT_SESSION_UNLOCK(session);
2403 NETAGENTLOG(LOG_ERR, "Payload length is invalid (%lu)", payload_length);
2404 response_error = EINVAL;
2405 goto done;
2406 }
2407
2408 uuid_t agent_uuid = {};
2409 uuid_copy(agent_uuid, payload);
2410 registration = netagent_session_find_agent_with_uuid_and_lock(session, agent_uuid, true, false);
2411 } else {
2412 registration = netagent_session_access_agent_with_lock(session, true, false);
2413 }
2414
2415 if (registration == NULL) {
2416 NETAGENT_SESSION_UNLOCK(session);
2417 NETAGENTLOG0(LOG_ERR, "Session has no agent registered");
2418 response_error = ENOENT;
2419 goto done;
2420 }
2421
2422 struct netagent_token *search_token = NULL;
2423 struct netagent_token *temp_token = NULL;
2424 TAILQ_FOREACH_SAFE(search_token, ®istration->token_list, token_chain, temp_token) {
2425 TAILQ_REMOVE(®istration->token_list, search_token, token_chain);
2426 netagent_token_free(search_token);
2427 }
2428 registration->last_client_error = 0;
2429 registration->client_error_count = 0;
2430
2431 NETAGENT_UNLOCK(registration);
2432 NETAGENT_SESSION_UNLOCK(session);
2433 done:
2434 return response_error;
2435 }
2436
2437 static errno_t
netagent_handle_enable_session_mode_setopt(struct netagent_session * session,__unused u_int8_t * payload,__unused size_t payload_length)2438 netagent_handle_enable_session_mode_setopt(struct netagent_session *session, __unused u_int8_t *payload, __unused size_t payload_length)
2439 {
2440 errno_t response_error = 0;
2441
2442 if (session == NULL) {
2443 NETAGENTLOG0(LOG_ERR, "Failed to find session");
2444 response_error = ENOENT;
2445 goto done;
2446 }
2447
2448 NETAGENT_SESSION_LOCK(session);
2449 if (!TAILQ_EMPTY(&session->registrations)) {
2450 NETAGENT_SESSION_UNLOCK(session);
2451 NETAGENTLOG0(LOG_ERR, "Session already has agent registered");
2452 response_error = EEXIST;
2453 goto done;
2454 }
2455
2456 session->allow_multiple_registrations = true;
2457 NETAGENT_SESSION_UNLOCK(session);
2458 done:
2459 return response_error;
2460 }
2461
2462 static struct netagent_registration *
netagent_find_agent_with_uuid_and_lock(uuid_t uuid,bool exclusively,bool ignore_lock)2463 netagent_find_agent_with_uuid_and_lock(uuid_t uuid, bool exclusively, bool ignore_lock)
2464 {
2465 NETAGENT_LIST_ASSERT_LOCKED();
2466
2467 struct netagent_registration *registration = NULL;
2468 LIST_FOREACH(registration, &shared_netagent_list, global_chain) {
2469 if (uuid_compare(registration->netagent->netagent_uuid, uuid) == 0) {
2470 if (!ignore_lock) {
2471 if (exclusively) {
2472 NETAGENT_LOCK_EXCLUSIVE(registration);
2473 } else {
2474 NETAGENT_LOCK_SHARED(registration);
2475 }
2476 }
2477 return registration;
2478 }
2479 }
2480
2481 return NULL;
2482 }
2483
2484 static struct netagent_registration *
netagent_session_find_agent_with_uuid_and_lock(struct netagent_session * session,uuid_t uuid,bool exclusively,bool ignore_lock)2485 netagent_session_find_agent_with_uuid_and_lock(struct netagent_session *session, uuid_t uuid, bool exclusively, bool ignore_lock)
2486 {
2487 NETAGENT_SESSION_ASSERT_LOCKED(session);
2488
2489 struct netagent_registration *registration = NULL;
2490 TAILQ_FOREACH(registration, &session->registrations, session_chain) {
2491 if (uuid_compare(registration->netagent->netagent_uuid, uuid) == 0) {
2492 if (!ignore_lock) {
2493 if (exclusively) {
2494 NETAGENT_LOCK_EXCLUSIVE(registration);
2495 } else {
2496 NETAGENT_LOCK_SHARED(registration);
2497 }
2498 }
2499 return registration;
2500 }
2501 }
2502
2503 return NULL;
2504 }
2505
2506 static struct netagent_registration *
netagent_session_access_agent_with_lock(struct netagent_session * session,bool exclusively,bool ignore_lock)2507 netagent_session_access_agent_with_lock(struct netagent_session *session, bool exclusively, bool ignore_lock)
2508 {
2509 NETAGENT_SESSION_ASSERT_LOCKED(session);
2510
2511 struct netagent_registration *registration = TAILQ_FIRST(&session->registrations);
2512 if (registration != NULL) {
2513 if (!ignore_lock) {
2514 if (exclusively) {
2515 NETAGENT_LOCK_EXCLUSIVE(registration);
2516 } else {
2517 NETAGENT_LOCK_SHARED(registration);
2518 }
2519 }
2520 }
2521
2522 return registration;
2523 }
2524
2525 void
netagent_post_updated_interfaces(uuid_t uuid)2526 netagent_post_updated_interfaces(uuid_t uuid)
2527 {
2528 if (!uuid_is_null(uuid)) {
2529 netagent_post_event(uuid, KEV_NETAGENT_UPDATED_INTERFACES, true, false);
2530 } else {
2531 NETAGENTLOG0(LOG_DEBUG, "Interface event with no associated agent");
2532 }
2533 }
2534
2535 static u_int32_t
netagent_dump_get_data_size_locked()2536 netagent_dump_get_data_size_locked()
2537 {
2538 NETAGENT_LIST_ASSERT_LOCKED();
2539
2540 struct netagent_registration *search_netagent = NULL;
2541 u_int32_t total_netagent_data_size = 0;
2542 // Traverse the shared list to know how much data the client needs to allocate to get the list of agent UUIDs
2543 LIST_FOREACH(search_netagent, &shared_netagent_list, global_chain) {
2544 total_netagent_data_size += sizeof(search_netagent->netagent->netagent_uuid);
2545 }
2546 return total_netagent_data_size;
2547 }
2548
2549 static void
netagent_dump_copy_data_locked(u_int8_t * __sized_by (buffer_length)buffer,u_int32_t buffer_length)2550 netagent_dump_copy_data_locked(u_int8_t * __sized_by(buffer_length)buffer, u_int32_t buffer_length)
2551 {
2552 NETAGENT_LIST_ASSERT_LOCKED();
2553
2554 size_t response_size = 0;
2555 u_int8_t * __indexable cursor = NULL;
2556 struct netagent_registration * __single search_netagent = NULL;
2557
2558 response_size = buffer_length; // We already know that buffer_length is the same as total_netagent_data_size.
2559 cursor = buffer;
2560 LIST_FOREACH(search_netagent, &shared_netagent_list, global_chain) {
2561 memcpy(cursor, search_netagent->netagent->netagent_uuid, sizeof(search_netagent->netagent->netagent_uuid));
2562 cursor += sizeof(search_netagent->netagent->netagent_uuid);
2563 }
2564 }
2565
2566 int
netagent_ioctl(u_long cmd,caddr_t __sized_by (IOCPARM_LEN (cmd))data)2567 netagent_ioctl(u_long cmd, caddr_t __sized_by(IOCPARM_LEN(cmd)) data)
2568 {
2569 int error = 0;
2570
2571 switch (cmd) {
2572 case SIOCGIFAGENTLIST32:
2573 case SIOCGIFAGENTLIST64: {
2574 /* Check entitlement if the client requests agent dump */
2575 errno_t cred_result = priv_check_cred(kauth_cred_get(), PRIV_NET_PRIVILEGED_NECP_POLICIES, 0);
2576 if (cred_result != 0) {
2577 NETAGENTLOG0(LOG_ERR, "Client does not hold the necessary entitlement to get netagent information");
2578 return EINVAL;
2579 }
2580 break;
2581 }
2582 default:
2583 break;
2584 }
2585
2586 NETAGENT_LIST_LOCK_SHARED();
2587 switch (cmd) {
2588 case SIOCGIFAGENTDATA32: {
2589 struct netagent_req32 *ifsir32 = (struct netagent_req32 *)(void *)data;
2590 struct netagent_registration *registration = netagent_find_agent_with_uuid_and_lock(ifsir32->netagent_uuid, false, false);
2591 if (registration == NULL) {
2592 error = ENOENT;
2593 break;
2594 }
2595 uuid_copy(ifsir32->netagent_uuid, registration->netagent->netagent_uuid);
2596 memcpy(ifsir32->netagent_domain, registration->netagent->netagent_domain, sizeof(ifsir32->netagent_domain));
2597 memcpy(ifsir32->netagent_type, registration->netagent->netagent_type, sizeof(ifsir32->netagent_type));
2598 memcpy(ifsir32->netagent_desc, registration->netagent->netagent_desc, sizeof(ifsir32->netagent_desc));
2599 ifsir32->netagent_flags = registration->netagent->netagent_flags;
2600 if (ifsir32->netagent_data_size == 0) {
2601 // First pass, client wants data size
2602 ifsir32->netagent_data_size = registration->netagent->netagent_data_size;
2603 } else if (ifsir32->netagent_data != USER_ADDR_NULL &&
2604 ifsir32->netagent_data_size == registration->netagent->netagent_data_size) {
2605 // Second pass, client wants data buffer filled out
2606 error = copyout(netagent_get_data(registration->netagent), ifsir32->netagent_data, registration->netagent->netagent_data_size);
2607 } else {
2608 error = EINVAL;
2609 }
2610 NETAGENT_UNLOCK(registration);
2611 break;
2612 }
2613 case SIOCGIFAGENTDATA64: {
2614 struct netagent_req64 *ifsir64 = (struct netagent_req64 *)(void *)data;
2615 struct netagent_registration *registration = netagent_find_agent_with_uuid_and_lock(ifsir64->netagent_uuid, false, false);
2616 if (registration == NULL) {
2617 error = ENOENT;
2618 break;
2619 }
2620 uuid_copy(ifsir64->netagent_uuid, registration->netagent->netagent_uuid);
2621 memcpy(ifsir64->netagent_domain, registration->netagent->netagent_domain, sizeof(ifsir64->netagent_domain));
2622 memcpy(ifsir64->netagent_type, registration->netagent->netagent_type, sizeof(ifsir64->netagent_type));
2623 memcpy(ifsir64->netagent_desc, registration->netagent->netagent_desc, sizeof(ifsir64->netagent_desc));
2624 ifsir64->netagent_flags = registration->netagent->netagent_flags;
2625 if (ifsir64->netagent_data_size == 0) {
2626 // First pass, client wants data size
2627 ifsir64->netagent_data_size = registration->netagent->netagent_data_size;
2628 } else if (ifsir64->netagent_data != USER_ADDR_NULL &&
2629 ifsir64->netagent_data_size == registration->netagent->netagent_data_size) {
2630 // Second pass, client wants data buffer filled out
2631 error = copyout(netagent_get_data(registration->netagent), ifsir64->netagent_data, registration->netagent->netagent_data_size);
2632 } else {
2633 error = EINVAL;
2634 }
2635 NETAGENT_UNLOCK(registration);
2636 break;
2637 }
2638 case SIOCGIFAGENTLIST32: {
2639 struct netagentlist_req32 *ifsir32 = (struct netagentlist_req32 *)(void *)data;
2640 if (ifsir32->data_size == 0) {
2641 // First pass, client wants data size
2642 ifsir32->data_size = netagent_dump_get_data_size_locked();
2643 } else if (ifsir32->data != USER_ADDR_NULL &&
2644 ifsir32->data_size > 0 &&
2645 ifsir32->data_size == netagent_dump_get_data_size_locked()) {
2646 // Second pass, client wants data buffer filled out
2647 u_int8_t *response = NULL;
2648 response = (u_int8_t *)kalloc_data(ifsir32->data_size, Z_NOWAIT | Z_ZERO);
2649 if (response == NULL) {
2650 error = ENOMEM;
2651 break;
2652 }
2653
2654 netagent_dump_copy_data_locked(response, ifsir32->data_size);
2655 error = copyout(response, ifsir32->data, ifsir32->data_size);
2656 kfree_data(response, ifsir32->data_size);
2657 } else {
2658 error = EINVAL;
2659 }
2660 break;
2661 }
2662 case SIOCGIFAGENTLIST64: {
2663 struct netagentlist_req64 *ifsir64 = (struct netagentlist_req64 *)(void *)data;
2664 if (ifsir64->data_size == 0) {
2665 // First pass, client wants data size
2666 ifsir64->data_size = netagent_dump_get_data_size_locked();
2667 } else if (ifsir64->data != USER_ADDR_NULL &&
2668 ifsir64->data_size > 0 &&
2669 ifsir64->data_size == netagent_dump_get_data_size_locked()) {
2670 // Second pass, client wants data buffer filled out
2671 u_int8_t *response = NULL;
2672 response = (u_int8_t *)kalloc_data(ifsir64->data_size, Z_NOWAIT | Z_ZERO);
2673 if (response == NULL) {
2674 error = ENOMEM;
2675 break;
2676 }
2677
2678 netagent_dump_copy_data_locked(response, ifsir64->data_size);
2679 error = copyout(response, ifsir64->data, ifsir64->data_size);
2680 kfree_data(response, ifsir64->data_size);
2681 } else {
2682 error = EINVAL;
2683 }
2684 break;
2685 }
2686 default: {
2687 error = EINVAL;
2688 break;
2689 }
2690 }
2691 NETAGENT_LIST_UNLOCK();
2692 return error;
2693 }
2694
2695 u_int32_t
netagent_get_flags(uuid_t uuid)2696 netagent_get_flags(uuid_t uuid)
2697 {
2698 u_int32_t flags = 0;
2699 NETAGENT_LIST_LOCK_SHARED();
2700 struct netagent_registration *registration = netagent_find_agent_with_uuid_and_lock(uuid, false, false);
2701 if (registration != NULL) {
2702 flags = registration->netagent->netagent_flags;
2703 NETAGENT_UNLOCK(registration);
2704 } else {
2705 NETAGENTLOG0(LOG_DEBUG, "Flags requested for invalid netagent");
2706 }
2707 NETAGENT_LIST_UNLOCK();
2708
2709 return flags;
2710 }
2711
2712 errno_t
netagent_set_flags(uuid_t uuid,u_int32_t flags)2713 netagent_set_flags(uuid_t uuid, u_int32_t flags)
2714 {
2715 errno_t error = 0;
2716 bool updated = false;
2717
2718 NETAGENT_LIST_LOCK_SHARED();
2719 struct netagent_registration *registration = netagent_find_agent_with_uuid_and_lock(uuid, true, false);
2720 if (registration != NULL) {
2721 // Don't allow the clients to clear
2722 // NETAGENT_FLAG_REGISTERED.
2723 uint32_t registered =
2724 registration->netagent->netagent_flags & NETAGENT_FLAG_REGISTERED;
2725 flags |= registered;
2726 if (registration->netagent->netagent_flags != flags) {
2727 registration->netagent->netagent_flags = flags;
2728 registration->generation = g_next_generation++;
2729 updated = true;
2730 }
2731 NETAGENT_UNLOCK(registration);
2732 } else {
2733 NETAGENTLOG0(LOG_DEBUG,
2734 "Attempt to set flags for invalid netagent");
2735 error = ENOENT;
2736 }
2737 NETAGENT_LIST_UNLOCK();
2738 if (updated) {
2739 netagent_post_event(uuid, KEV_NETAGENT_UPDATED, true, false);
2740 }
2741
2742 return error;
2743 }
2744
2745 u_int32_t
netagent_get_generation(uuid_t uuid)2746 netagent_get_generation(uuid_t uuid)
2747 {
2748 u_int32_t generation = 0;
2749 NETAGENT_LIST_LOCK_SHARED();
2750 struct netagent_registration *registration = netagent_find_agent_with_uuid_and_lock(uuid, false, false);
2751 if (registration != NULL) {
2752 generation = registration->generation;
2753 NETAGENT_UNLOCK(registration);
2754 } else {
2755 NETAGENTLOG0(LOG_DEBUG, "Generation requested for invalid netagent");
2756 }
2757 NETAGENT_LIST_UNLOCK();
2758
2759 return generation;
2760 }
2761
2762 bool
netagent_get_agent_domain_and_type(uuid_t uuid,char * __sized_by (NETAGENT_DOMAINSIZE)domain,char * __sized_by (NETAGENT_TYPESIZE)type)2763 netagent_get_agent_domain_and_type(uuid_t uuid, char * __sized_by(NETAGENT_DOMAINSIZE)domain, char * __sized_by(NETAGENT_TYPESIZE)type)
2764 {
2765 bool found = FALSE;
2766 if (domain == NULL || type == NULL) {
2767 NETAGENTLOG(LOG_ERR, "Invalid arguments for netagent_get_agent_domain_and_type %p %p", domain, type);
2768 return FALSE;
2769 }
2770
2771 NETAGENT_LIST_LOCK_SHARED();
2772 struct netagent_registration *registration = netagent_find_agent_with_uuid_and_lock(uuid, false, false);
2773 if (registration != NULL) {
2774 found = TRUE;
2775 memcpy(domain, registration->netagent->netagent_domain, NETAGENT_DOMAINSIZE);
2776 memcpy(type, registration->netagent->netagent_type, NETAGENT_TYPESIZE);
2777 NETAGENT_UNLOCK(registration);
2778 } else {
2779 NETAGENTLOG0(LOG_ERR, "Type requested for invalid netagent");
2780 }
2781 NETAGENT_LIST_UNLOCK();
2782
2783 return found;
2784 }
2785
2786 int
netagent_kernel_trigger(uuid_t uuid)2787 netagent_kernel_trigger(uuid_t uuid)
2788 {
2789 int error = 0;
2790
2791 NETAGENT_LIST_LOCK_SHARED();
2792 struct netagent_registration *registration = netagent_find_agent_with_uuid_and_lock(uuid, false, false);
2793 if (registration == NULL) {
2794 NETAGENTLOG0(LOG_ERR, "Requested netagent for kernel trigger could not be found");
2795 error = ENOENT;
2796 goto done;
2797 }
2798
2799 if ((registration->netagent->netagent_flags & NETAGENT_FLAG_KERNEL_ACTIVATED) == 0) {
2800 NETAGENTLOG0(LOG_ERR, "Requested netagent for kernel trigger is not kernel activated");
2801 // Agent does not accept kernel triggers
2802 error = EINVAL;
2803 goto done;
2804 }
2805
2806 if ((registration->netagent->netagent_flags & NETAGENT_FLAG_ACTIVE)) {
2807 // Agent already active
2808 NETAGENTLOG0(LOG_INFO, "Requested netagent for kernel trigger is already active");
2809 error = 0;
2810 goto done;
2811 }
2812
2813 error = netagent_send_trigger(registration, current_proc(), NETAGENT_TRIGGER_FLAG_KERNEL, NETAGENT_MESSAGE_TYPE_TRIGGER);
2814 NETAGENTLOG((error ? LOG_ERR : LOG_INFO), "Triggered netagent from kernel (error %d)", error);
2815 done:
2816 if (registration != NULL) {
2817 NETAGENT_UNLOCK(registration);
2818 }
2819 NETAGENT_LIST_UNLOCK();
2820 return error;
2821 }
2822
2823 int
netagent_client_message_with_params(uuid_t agent_uuid,uuid_t necp_client_uuid,pid_t pid,void * handle,u_int8_t message_type,struct necp_client_agent_parameters * parameters,void * __sized_by (* assigned_results_length)* assigned_results,size_t * assigned_results_length)2824 netagent_client_message_with_params(uuid_t agent_uuid,
2825 uuid_t necp_client_uuid,
2826 pid_t pid,
2827 void *handle,
2828 u_int8_t message_type,
2829 struct necp_client_agent_parameters *parameters,
2830 void * __sized_by(*assigned_results_length) *assigned_results,
2831 size_t *assigned_results_length)
2832 {
2833 int error = 0;
2834
2835 if (message_type != NETAGENT_MESSAGE_TYPE_CLIENT_TRIGGER &&
2836 message_type != NETAGENT_MESSAGE_TYPE_CLIENT_ASSERT &&
2837 message_type != NETAGENT_MESSAGE_TYPE_CLIENT_UNASSERT &&
2838 message_type != NETAGENT_MESSAGE_TYPE_CLIENT_ERROR &&
2839 message_type != NETAGENT_MESSAGE_TYPE_REQUEST_NEXUS &&
2840 message_type != NETAGENT_MESSAGE_TYPE_CLOSE_NEXUS &&
2841 message_type != NETAGENT_MESSAGE_TYPE_ABORT_NEXUS &&
2842 message_type != NETAGENT_MESSAGE_TYPE_ADD_GROUP_MEMBERS &&
2843 message_type != NETAGENT_MESSAGE_TYPE_REMOVE_GROUP_MEMBERS) {
2844 NETAGENTLOG(LOG_ERR, "Client netagent message type (%d) is invalid", message_type);
2845 return EINVAL;
2846 }
2847
2848 NETAGENT_LIST_LOCK_SHARED();
2849 bool should_unlock_list = true;
2850 bool should_unlock_registration = true;
2851 struct netagent_registration *registration = netagent_find_agent_with_uuid_and_lock(agent_uuid, false, false);
2852 if (registration == NULL) {
2853 NETAGENTLOG0(LOG_DEBUG, "Requested netagent for nexus instance could not be found");
2854 error = ENOENT;
2855 goto done;
2856 }
2857
2858 if (message_type == NETAGENT_MESSAGE_TYPE_CLIENT_TRIGGER) {
2859 if ((registration->netagent->netagent_flags & NETAGENT_FLAG_USER_ACTIVATED) == 0) {
2860 // Agent does not accept user triggers
2861 // Don't log, since this is a common case used to trigger events that cellular data is blocked, etc.
2862 error = ENOTSUP;
2863
2864
2865 pid_t report_pid = 0;
2866 uuid_t report_proc_uuid = {};
2867 if (parameters != NULL) {
2868 report_pid = parameters->u.nexus_request.epid;
2869 uuid_copy(report_proc_uuid, parameters->u.nexus_request.euuid);
2870 } else {
2871 struct proc *p = current_proc();
2872 if (p != NULL) {
2873 report_pid = proc_pid(p);
2874 proc_getexecutableuuid(p, report_proc_uuid, sizeof(report_proc_uuid));
2875 }
2876 }
2877 netagent_send_cellular_failed_event(registration, report_pid, report_proc_uuid);
2878 goto done;
2879 }
2880 } else if (message_type == NETAGENT_MESSAGE_TYPE_REQUEST_NEXUS ||
2881 message_type == NETAGENT_MESSAGE_TYPE_CLOSE_NEXUS ||
2882 message_type == NETAGENT_MESSAGE_TYPE_ABORT_NEXUS) {
2883 bool is_nexus_agent = ((registration->netagent->netagent_flags &
2884 (NETAGENT_FLAG_NEXUS_PROVIDER |
2885 NETAGENT_FLAG_NEXUS_LISTENER |
2886 NETAGENT_FLAG_CUSTOM_IP_NEXUS |
2887 NETAGENT_FLAG_CUSTOM_ETHER_NEXUS |
2888 NETAGENT_FLAG_INTERPOSE_NEXUS)) != 0);
2889 if (!is_nexus_agent) {
2890 NETAGENTLOG0(LOG_ERR, "Requested netagent for nexus instance is not a nexus provider");
2891 // Agent is not a nexus provider
2892 error = EINVAL;
2893 goto done;
2894 }
2895
2896 if ((registration->netagent->netagent_flags & NETAGENT_FLAG_ACTIVE) == 0) {
2897 // Agent not active
2898 NETAGENTLOG0(LOG_INFO, "Requested netagent for nexus instance is not active");
2899 error = EINVAL;
2900 goto done;
2901 }
2902 } else if (message_type == NETAGENT_MESSAGE_TYPE_ADD_GROUP_MEMBERS ||
2903 message_type == NETAGENT_MESSAGE_TYPE_REMOVE_GROUP_MEMBERS) {
2904 bool is_group_agent = ((registration->netagent->netagent_flags & (NETAGENT_FLAG_SUPPORTS_GROUPS)) != 0);
2905 if (!is_group_agent) {
2906 NETAGENTLOG0(LOG_ERR, "Requested netagent for group operation is not a group provider");
2907 error = EINVAL;
2908 goto done;
2909 }
2910
2911 if ((registration->netagent->netagent_flags & NETAGENT_FLAG_ACTIVE) == 0) {
2912 // Agent not active
2913 NETAGENTLOG0(LOG_INFO, "Requested netagent for group operation is not active");
2914 error = EINVAL;
2915 goto done;
2916 }
2917 }
2918
2919 if (registration->control_unit == 0) {
2920 if (registration->event_handler == NULL) {
2921 // No event handler registered for kernel agent
2922 error = EINVAL;
2923 } else {
2924 // We hold the registration lock during the event handler callout, so it is expected
2925 // that the event handler will not lead to any registrations or unregistrations
2926 // of network agents.
2927 // We release the list lock before calling the event handler to allow other threads
2928 // to access the list while the event is processing.
2929 NETAGENT_LIST_UNLOCK();
2930 should_unlock_list = false;
2931 error = registration->event_handler(message_type, necp_client_uuid, pid, handle,
2932 registration->event_context, parameters,
2933 assigned_results, assigned_results_length);
2934 if (error != 0) {
2935 VERIFY(assigned_results == NULL || *assigned_results == NULL);
2936 VERIFY(assigned_results_length == NULL || *assigned_results_length == 0);
2937 }
2938 }
2939 } else {
2940 // ABORT_NEXUS is kernel-private, so translate it for userspace nexus
2941 if (message_type == NETAGENT_MESSAGE_TYPE_ABORT_NEXUS) {
2942 message_type = NETAGENT_MESSAGE_TYPE_CLOSE_NEXUS;
2943 }
2944
2945 if (message_type == NETAGENT_MESSAGE_TYPE_CLIENT_ERROR) {
2946 const int32_t client_error = parameters->u.error.error;
2947 const bool force_report = parameters->u.error.force_report;
2948 if (registration->last_client_error != client_error || // Always notify for an error change
2949 force_report || // Always notify if force reporting was requested
2950 (client_error == 0 && registration->client_error_count == 0) || // Only notify once for no-error
2951 (client_error != 0 && registration->client_error_count < NETAGENT_MAX_CLIENT_ERROR_COUNT)) {
2952 if (NETAGENT_LOCK_SHARED_TO_EXCLUSIVE(registration)) {
2953 if (registration->last_client_error != client_error) {
2954 registration->last_client_error = client_error;
2955 registration->client_error_count = 1;
2956 } else {
2957 registration->client_error_count++;
2958 }
2959 error = netagent_send_error_message(registration, necp_client_uuid, message_type, client_error);
2960 } else {
2961 // If NETAGENT_LOCK_SHARED_TO_EXCLUSIVE fails, it unlocks automatically
2962 should_unlock_registration = false;
2963 }
2964 }
2965 } else if (message_type == NETAGENT_MESSAGE_TYPE_ADD_GROUP_MEMBERS ||
2966 message_type == NETAGENT_MESSAGE_TYPE_REMOVE_GROUP_MEMBERS) {
2967 error = netagent_send_group_message(registration, necp_client_uuid, message_type, ¶meters->u.group_members);
2968 } else {
2969 error = netagent_send_client_message(registration, necp_client_uuid, message_type);
2970 }
2971 if (error == 0 && message_type == NETAGENT_MESSAGE_TYPE_CLIENT_TRIGGER) {
2972 if (NETAGENT_LOCK_SHARED_TO_EXCLUSIVE(registration)) {
2973 // Grab the lock exclusively to add a pending client to the list
2974 struct netagent_client *new_pending_client = NULL;
2975 new_pending_client = kalloc_type(struct netagent_client, Z_WAITOK);
2976 if (new_pending_client == NULL) {
2977 NETAGENTLOG0(LOG_ERR, "Failed to allocate client for trigger");
2978 } else {
2979 uuid_copy(new_pending_client->client_id, necp_client_uuid);
2980 if (parameters != NULL) {
2981 new_pending_client->client_pid = parameters->u.nexus_request.epid;
2982 uuid_copy(new_pending_client->client_proc_uuid, parameters->u.nexus_request.euuid);
2983 } else {
2984 struct proc *p = current_proc();
2985 if (p != NULL) {
2986 new_pending_client->client_pid = proc_pid(p);
2987 proc_getexecutableuuid(p, new_pending_client->client_proc_uuid, sizeof(new_pending_client->client_proc_uuid));
2988 }
2989 }
2990 LIST_INSERT_HEAD(®istration->pending_triggers_list, new_pending_client, client_chain);
2991 }
2992 } else {
2993 // If NETAGENT_LOCK_SHARED_TO_EXCLUSIVE fails, it unlocks automatically
2994 should_unlock_registration = false;
2995 }
2996 }
2997 }
2998 NETAGENTLOG(((error && error != ENOENT) ? LOG_ERR : LOG_INFO), "Send message %d for client (error %d)", message_type, error);
2999 if (message_type == NETAGENT_MESSAGE_TYPE_CLIENT_TRIGGER) {
3000 uuid_string_t uuid_str;
3001 uuid_unparse(agent_uuid, uuid_str);
3002 NETAGENTLOG(LOG_NOTICE, "Triggered network agent %s, error = %d", uuid_str, error);
3003 }
3004 done:
3005 if (should_unlock_registration && registration != NULL) {
3006 NETAGENT_UNLOCK(registration);
3007 }
3008 if (should_unlock_list) {
3009 NETAGENT_LIST_UNLOCK();
3010 }
3011 return error;
3012 }
3013
3014 int
netagent_client_message(uuid_t agent_uuid,uuid_t necp_client_uuid,pid_t pid,void * handle,u_int8_t message_type)3015 netagent_client_message(uuid_t agent_uuid, uuid_t necp_client_uuid, pid_t pid, void *handle, u_int8_t message_type)
3016 {
3017 size_t dummy_length = 0;
3018 void *dummy_results __sized_by(dummy_length) = NULL;
3019
3020 return netagent_client_message_with_params(agent_uuid, necp_client_uuid, pid, handle, message_type, NULL, &dummy_results, &dummy_length);
3021 }
3022
3023 int
netagent_use(uuid_t agent_uuid,uint64_t * out_use_count)3024 netagent_use(uuid_t agent_uuid, uint64_t *out_use_count)
3025 {
3026 int error = 0;
3027
3028 NETAGENT_LIST_LOCK_SHARED();
3029 struct netagent_registration *registration = netagent_find_agent_with_uuid_and_lock(agent_uuid, true, false);
3030 if (registration == NULL) {
3031 NETAGENTLOG0(LOG_ERR, "netagent_assert: Requested netagent UUID is not registered");
3032 error = ENOENT;
3033 goto done;
3034 }
3035
3036 uint64_t current_count = registration->use_count;
3037 registration->use_count++;
3038
3039 if (out_use_count != NULL) {
3040 *out_use_count = current_count;
3041 }
3042
3043 done:
3044 if (registration != NULL) {
3045 NETAGENT_UNLOCK(registration);
3046 }
3047 NETAGENT_LIST_UNLOCK();
3048 return error;
3049 }
3050
3051 int
netagent_copyout(uuid_t agent_uuid,user_addr_t user_addr,u_int32_t user_size)3052 netagent_copyout(uuid_t agent_uuid, user_addr_t user_addr, u_int32_t user_size)
3053 {
3054 int error = 0;
3055
3056 NETAGENT_LIST_LOCK_SHARED();
3057 struct netagent_registration *registration = netagent_find_agent_with_uuid_and_lock(agent_uuid, false, false);
3058 if (registration == NULL) {
3059 NETAGENTLOG0(LOG_DEBUG, "Requested netagent for nexus instance could not be found");
3060 error = ENOENT;
3061 goto done;
3062 }
3063
3064 u_int32_t total_size = (sizeof(struct netagent) + registration->netagent->netagent_data_size);
3065 if (user_size < total_size) {
3066 NETAGENTLOG(LOG_ERR, "Provided user buffer is too small (%u < %u)", user_size, total_size);
3067 error = EINVAL;
3068 goto done;
3069 }
3070
3071 u_int8_t *ptr = __unsafe_forge_bidi_indexable(u_int8_t *, registration->netagent, total_size);
3072 error = copyout(ptr, user_addr, total_size);
3073
3074 NETAGENTLOG((error ? LOG_ERR : LOG_DEBUG), "Copied agent content (error %d)", error);
3075 done:
3076 if (registration != NULL) {
3077 NETAGENT_UNLOCK(registration);
3078 }
3079 NETAGENT_LIST_UNLOCK();
3080 return error;
3081 }
3082
3083 #define NETAGENT_TOKEN_EVENT_INTERVAL_NSEC (NSEC_PER_SEC * 10) // Only fire repeated events up to once every 10 seconds
3084
3085 int
netagent_acquire_token(uuid_t agent_uuid,user_addr_t user_addr,u_int32_t user_size,int * retval)3086 netagent_acquire_token(uuid_t agent_uuid, user_addr_t user_addr, u_int32_t user_size, int *retval)
3087 {
3088 int error = 0;
3089
3090 NETAGENT_LIST_LOCK_SHARED();
3091 struct netagent_registration *registration = netagent_find_agent_with_uuid_and_lock(agent_uuid, true, false);
3092 if (registration == NULL) {
3093 NETAGENTLOG0(LOG_DEBUG, "Network agent for request UUID could not be found");
3094 error = ENOENT;
3095 goto done;
3096 }
3097
3098 struct netagent_token *token = TAILQ_FIRST(®istration->token_list);
3099 if (token == NULL) {
3100 NETAGENTLOG0(LOG_DEBUG, "Network agent does not have any tokens");
3101 if (registration->token_low_water != 0) {
3102 // Only fire an event if one hasn't occurred in the last 10 seconds
3103 if (mach_absolute_time() >= registration->need_tokens_event_deadline) {
3104 int event_error = netagent_send_tokens_needed(registration);
3105 if (event_error == 0) {
3106 // Reset the deadline
3107 uint64_t deadline = 0;
3108 nanoseconds_to_absolutetime(NETAGENT_TOKEN_EVENT_INTERVAL_NSEC, &deadline);
3109 clock_absolutetime_interval_to_deadline(deadline, &deadline);
3110 registration->need_tokens_event_deadline = deadline;
3111 }
3112 }
3113 }
3114 error = ENODATA;
3115 goto done;
3116 }
3117
3118 if (user_size < token->token_length) {
3119 NETAGENTLOG(LOG_ERR, "Provided user buffer is too small (%u < %u)", user_size, token->token_length);
3120 error = EMSGSIZE;
3121 goto done;
3122 }
3123
3124 error = copyout(token->token_bytes, user_addr, token->token_length);
3125 if (error == 0) {
3126 *retval = (int)token->token_length;
3127 }
3128
3129 NETAGENTLOG((error ? LOG_ERR : LOG_DEBUG), "Copied token content (error %d)", error);
3130
3131 TAILQ_REMOVE(®istration->token_list, token, token_chain);
3132 netagent_token_free(token);
3133 if (registration->token_count > 0) {
3134 registration->token_count--;
3135 }
3136 if (registration->token_count < registration->token_low_water) {
3137 (void)netagent_send_tokens_needed(registration);
3138 }
3139 done:
3140 if (registration != NULL) {
3141 NETAGENT_UNLOCK(registration);
3142 }
3143 NETAGENT_LIST_UNLOCK();
3144 return error;
3145 }
3146
3147 int
netagent_trigger(struct proc * p,struct netagent_trigger_args * uap,int32_t * retval)3148 netagent_trigger(struct proc *p, struct netagent_trigger_args *uap, int32_t *retval)
3149 {
3150 #pragma unused(p, retval)
3151 uuid_t agent_uuid = {};
3152 int error = 0;
3153
3154 if (uap == NULL) {
3155 NETAGENTLOG0(LOG_ERR, "uap == NULL");
3156 return EINVAL;
3157 }
3158
3159 if (uap->agent_uuid) {
3160 if (uap->agent_uuidlen != sizeof(uuid_t)) {
3161 NETAGENTLOG(LOG_ERR, "Incorrect length (got %zu, expected %lu)",
3162 (size_t)uap->agent_uuidlen, sizeof(uuid_t));
3163 return ERANGE;
3164 }
3165
3166 error = copyin(uap->agent_uuid, agent_uuid, sizeof(uuid_t));
3167 if (error) {
3168 NETAGENTLOG(LOG_ERR, "copyin error (%d)", error);
3169 return error;
3170 }
3171 }
3172
3173 if (uuid_is_null(agent_uuid)) {
3174 NETAGENTLOG0(LOG_ERR, "Requested netagent UUID is empty");
3175 return EINVAL;
3176 }
3177
3178 NETAGENT_LIST_LOCK_SHARED();
3179 struct netagent_registration *registration = netagent_find_agent_with_uuid_and_lock(agent_uuid, false, false);
3180 if (registration == NULL) {
3181 NETAGENTLOG0(LOG_ERR, "Requested netagent UUID is not registered");
3182 error = ENOENT;
3183 goto done;
3184 }
3185
3186 if ((registration->netagent->netagent_flags & NETAGENT_FLAG_USER_ACTIVATED) == 0) {
3187 // Agent does not accept triggers
3188 NETAGENTLOG0(LOG_ERR, "Requested netagent UUID is not eligible for triggering");
3189 error = ENOTSUP;
3190 goto done;
3191 }
3192
3193 if ((registration->netagent->netagent_flags & NETAGENT_FLAG_ACTIVE)) {
3194 // Agent already active
3195 NETAGENTLOG0(LOG_INFO, "Requested netagent UUID is already active");
3196 error = 0;
3197 goto done;
3198 }
3199
3200 error = netagent_send_trigger(registration, p, NETAGENT_TRIGGER_FLAG_USER, NETAGENT_MESSAGE_TYPE_TRIGGER);
3201 NETAGENTLOG((error ? LOG_ERR : LOG_INFO), "Triggered netagent (error %d)", error);
3202 done:
3203 if (registration != NULL) {
3204 NETAGENT_UNLOCK(registration);
3205 }
3206 NETAGENT_LIST_UNLOCK();
3207 return error;
3208 }
3209