xref: /xnu-12377.41.6/bsd/net/kctl_test.c (revision bbb1b6f9e71b8cdde6e5cd6f4841f207dee3d828)
1 /*
2  * Copyright (c) 2023 Apple Computer, Inc. All rights reserved.
3  *
4  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5  *
6  * This file contains Original Code and/or Modifications of Original Code
7  * as defined in and that are subject to the Apple Public Source License
8  * Version 2.0 (the 'License'). You may not use this file except in
9  * compliance with the License. The rights granted to you under the License
10  * may not be used to create, or enable the creation or redistribution of,
11  * unlawful or unlicensed copies of an Apple operating system, or to
12  * circumvent, violate, or enable the circumvention or violation of, any
13  * terms of an Apple operating system software license agreement.
14  *
15  * Please obtain a copy of the License at
16  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17  *
18  * The Original Code and all software distributed under the License are
19  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23  * Please see the License for the specific language governing rights and
24  * limitations under the License.
25  *
26  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27  */
28 
29 #include <mach/vm_types.h>
30 #include <mach/kmod.h>
31 #include <sys/socket.h>
32 #include <sys/syslog.h>
33 #include <sys/errno.h>
34 #include <netinet/in.h>
35 
36 #include <sys/kern_control.h>
37 #include <libkern/libkern.h>
38 #include <os/log.h>
39 
40 #include <net/kctl_test.h>
41 
42 static errno_t kctl_test_connect(kern_ctl_ref kctlref, struct sockaddr_ctl *sac, void **unitinfo);
43 static errno_t kctl_test_disconnect(kern_ctl_ref kctlref, u_int32_t unit, void *unitinfo);
44 static errno_t kctl_test_send(kern_ctl_ref kctlref, u_int32_t unit, void *unitinfo, mbuf_t m, int flags);
45 static errno_t kctl_test_setopt(kern_ctl_ref kctlref, u_int32_t unit, void *unitinfo, int opt, void *data, size_t len);
46 static errno_t kctl_test_getopt(kern_ctl_ref kctlref, u_int32_t unit, void *unitinfo, int opt, void *data, size_t *len);
47 static errno_t kctl_test_send_list(kern_ctl_ref kctlref, u_int32_t unit,
48     void *unitinfo, mbuf_t m, int flags);
49 
50 static struct kern_ctl_reg kctl_test_reg = {
51 	.ctl_name = KCTL_TEST_CONTROL_NAME,
52 	.ctl_id = 0,
53 	.ctl_unit = 0,
54 	.ctl_flags = CTL_FLAG_PRIVILEGED | CTL_FLAG_REG_EXTENDED,
55 	.ctl_sendsize = 256 * 1024, /* 256 KiB */
56 	.ctl_recvsize = 2 * 1024 * 1024, /* 2 MiB */
57 	.ctl_connect = kctl_test_connect,
58 	.ctl_disconnect = kctl_test_disconnect,
59 	.ctl_send = kctl_test_send,
60 	.ctl_setopt = kctl_test_setopt,
61 	.ctl_getopt = kctl_test_getopt,
62 	.ctl_send_list = kctl_test_send_list
63 };
64 static kern_ctl_ref kctl_test_ref;
65 static u_int32_t kctl_test_id;
66 
67 
68 static errno_t
kctl_test_connect(kern_ctl_ref kctlref,struct sockaddr_ctl * sac,void ** unitinfo)69 kctl_test_connect(kern_ctl_ref kctlref, struct sockaddr_ctl *sac, void **unitinfo)
70 {
71 #pragma unused(unitinfo)
72 	errno_t error = 0;
73 	size_t space;
74 
75 	os_log(OS_LOG_DEFAULT, "kctl_test_connect: ref %p id %u port %u",
76 	    kctlref, sac->sc_id, sac->sc_unit);
77 
78 	error = ctl_getenqueuespace(kctlref, sac->sc_unit, &space);
79 	if (error != 0) {
80 		os_log(OS_LOG_DEFAULT, "kctl_test_connect; ctl_getenqueuespace failed %d", error);
81 		goto out;
82 	}
83 	os_log(OS_LOG_DEFAULT, "kctl_test_connect: ctl_getenqueuespace %ld", space);
84 out:
85 	return error;
86 }
87 
88 static errno_t
kctl_test_disconnect(kern_ctl_ref kctlref,u_int32_t unit,void * unitinfo)89 kctl_test_disconnect(kern_ctl_ref kctlref, u_int32_t unit, void *unitinfo)
90 {
91 #pragma unused(unitinfo)
92 	errno_t error = 0;
93 	size_t space;
94 
95 	os_log(OS_LOG_DEFAULT, "kctl_test_disconnect: ref %p", kctlref);
96 
97 	error = ctl_getenqueuespace(kctlref, unit, &space);
98 	if (error != 0) {
99 		os_log(OS_LOG_DEFAULT, "kctl_test_disconnect; ctl_getenqueuespace failed %d", error);
100 		goto out;
101 	}
102 	os_log(OS_LOG_DEFAULT, "kctl_test_disconnect: ctl_getenqueuespace %ld", space);
103 out:
104 
105 	return error;
106 }
107 
108 static errno_t
kctl_test_send(kern_ctl_ref kctlref,u_int32_t unit,void * unitinfo,mbuf_t m,int flags)109 kctl_test_send(kern_ctl_ref kctlref, u_int32_t unit, void *unitinfo, mbuf_t m, int flags)
110 {
111 #pragma unused(unitinfo, flags)
112 	errno_t error = 0;
113 
114 	error = ctl_enqueuembuf(kctlref, unit, m, CTL_DATA_EOR);
115 	if (error != 0) {
116 		os_log(OS_LOG_DEFAULT, "kctl_test_send: ctl_enqueuembuf() failed %d", error);
117 		mbuf_freem(m);
118 	}
119 
120 	return error;
121 }
122 
123 static int optval = 0;
124 
125 static errno_t
kctl_test_setopt(kern_ctl_ref kctlref,u_int32_t unit,void * unitinfo,int opt,void * data,size_t len)126 kctl_test_setopt(kern_ctl_ref kctlref, u_int32_t unit, void *unitinfo, int opt, void *data, size_t len)
127 {
128 #pragma unused(unit, unitinfo)
129 	errno_t error = 0;
130 
131 	os_log(OS_LOG_DEFAULT, "kctl_test_setopt: ref %p", kctlref);
132 
133 	switch (opt) {
134 	case 0:
135 		if (len < sizeof(int)) {
136 			error = EINVAL;
137 		} else {
138 			optval = *(int*)data;
139 		}
140 		break;
141 	default:
142 		error = ENOPROTOOPT;
143 		break;
144 	}
145 
146 	return error;
147 }
148 
149 static errno_t
kctl_test_getopt(kern_ctl_ref kctlref,u_int32_t unit,void * unitinfo,int opt,void * data,size_t * len)150 kctl_test_getopt(kern_ctl_ref kctlref, u_int32_t unit, void *unitinfo, int opt, void *data, size_t *len)
151 {
152 #pragma unused(unitinfo, unit)
153 	errno_t error = 0;
154 
155 	os_log(OS_LOG_DEFAULT, "kctl_test_getopt: ref %p", kctlref);
156 
157 	switch (opt) {
158 	case 0:
159 		if (*len < sizeof(int)) {
160 			error = EINVAL;
161 		} else {
162 			*(int*)data = optval;
163 			*len = sizeof(int);
164 		}
165 		break;
166 	default:
167 		error = ENOPROTOOPT;
168 		break;
169 	}
170 
171 	return error;
172 }
173 
174 static errno_t
kctl_test_send_list(kern_ctl_ref kctlref,u_int32_t unit,void * unitinfo,mbuf_t m,int flags)175 kctl_test_send_list(kern_ctl_ref kctlref, u_int32_t unit,
176     void *unitinfo, mbuf_t m, int flags)
177 {
178 #pragma unused(unitinfo)
179 	errno_t error = 0;
180 	mbuf_ref_t m_remain = NULL;
181 	uint32_t unsent_count = 0;
182 
183 	error = ctl_enqueuembuf_list(kctlref, unit, m, flags, &m_remain);
184 	if (m_remain != NULL) {
185 		mbuf_ref_t tmp = m_remain;
186 
187 		while (tmp != NULL) {
188 			unsent_count += 1;
189 			tmp = mbuf_next(tmp);
190 		}
191 
192 		mbuf_freem_list(m_remain);
193 	}
194 	if (error != 0) {
195 		os_log(OS_LOG_DEFAULT, "kctl_test_send_list: ctl_enqueuembuf_list() error %d unsent packets %u",
196 		    error, unsent_count);
197 	}
198 	return error;
199 }
200 
201 int
kctl_test_init(void)202 kctl_test_init(void)
203 {
204 	errno_t error = 0;
205 	struct kern_ctl_reg kern_ctl_reg = kctl_test_reg;
206 
207 	os_log(OS_LOG_DEFAULT, "kctl_test_init ctl_sendsize %u ctl_recvsize %u",
208 	    kctl_test_reg.ctl_sendsize, kctl_test_reg.ctl_recvsize);
209 
210 	error = ctl_register(&kern_ctl_reg, &kctl_test_ref);
211 	if (error == 0) {
212 		kctl_test_id = kern_ctl_reg.ctl_id;
213 		os_log(OS_LOG_DEFAULT, "kctl_test_register: OK kctlref %p kctlid %x ctl_sendsize %u ctl_recvsize %u",
214 		    kctl_test_ref, kctl_test_id, kern_ctl_reg.ctl_sendsize, kern_ctl_reg.ctl_recvsize);
215 	} else {
216 		os_log(OS_LOG_DEFAULT, "kctl_test_register: error %d", error);
217 	}
218 	return (error == 0) ? KERN_SUCCESS : KERN_FAILURE;
219 }
220