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