1/*
2 * Copyright (c) 2010-2021 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29#include <string.h>
30#include <stdint.h>
31#include <stdbool.h>
32
33#include <mach/mach_types.h>
34
35#include <kern/kalloc.h>
36#include <kern/locks.h>
37#include <kern/debug.h>
38
39#include <sys/kernel.h>
40#include <sys/param.h>
41#include <sys/sockio.h>
42#include <sys/socket.h>
43#include <sys/queue.h>
44#include <sys/cdefs.h>
45#include <sys/kern_control.h>
46#include <sys/mbuf.h>
47#include <sys/sysctl.h>
48
49#include <net/if_types.h>
50#include <net/if.h>
51#include <net/kpi_interface.h>
52#include <net/bpf.h>
53#include <net/remote_vif.h>
54
55#include <libkern/libkern.h>
56#include <libkern/OSAtomic.h>
57
58#include <os/log.h>
59
60#define RVI_IF_NAME "rvi"
61
62#define RVI_DIR_IN IFF_LINK0
63#define RVI_DIR_OUT IFF_LINK1
64#define RVI_DIR_INOUT (RVI_DIR_IN | RVI_DIR_OUT)
65
66#define RVI_IF_FAMILY IFNET_FAMILY_LOOPBACK
67#define RVI_IF_TYPE IFT_OTHER
68#define RVI_IF_FLAGS (IFF_UP | IFF_DEBUG | RVI_DIR_INOUT)
69
70struct rvi_client_t {
71 LIST_ENTRY(rvi_client_t) _cle;
72 ifnet_t _ifp;
73 uint32_t _unit;
74 uint32_t _vif;
75 uint32_t _raw_count;
76 uint32_t _pktap_count;
77};
78
79static LIST_HEAD(, rvi_client_t) _s_rvi_clients;
80
81static LCK_GRP_DECLARE(rvi_grp, "remote virtual interface lock");
82static LCK_RW_DECLARE(rvi_mtx, &rvi_grp);
83
84static kern_ctl_ref rvi_kernctl = NULL;
85
86kern_return_t rvi_start(kmod_info_t *, void *);
87kern_return_t rvi_stop(kmod_info_t *, void *);
88
89static void rvi_insert_client(struct rvi_client_t *);
90static errno_t rvi_create_if(struct rvi_client_t *);
91static errno_t rvi_destroy_if(struct rvi_client_t *);
92
93static inline void rvi_lock_shared(lck_rw_t *);
94static inline void rvi_lock_exclusive(lck_rw_t *);
95static inline void rvi_lock_done_shared(lck_rw_t *);
96static inline void rvi_lock_done_exclusive(lck_rw_t *);
97
98static errno_t rvi_output(ifnet_t, mbuf_t);
99static errno_t rvi_demux(ifnet_t, mbuf_t, char *, protocol_family_t *);
100static errno_t rvi_ioctl(ifnet_t, unsigned long, void *);
101static errno_t rvi_add_proto(ifnet_t, protocol_family_t, const struct ifnet_demux_desc *, uint32_t);
102static errno_t rvi_del_proto(ifnet_t, protocol_family_t);
103static errno_t rvi_set_bpf_tap(ifnet_t, uint32_t, bpf_tap_mode);
104static void rvi_detach(ifnet_t);
105
106static errno_t rvi_bpf_tap(ifnet_t, mbuf_t, int, struct rvi_client_t *, struct pktap_header *);
107
108static errno_t rvi_register_control(void);
109static errno_t rvi_ctl_connect(kern_ctl_ref, struct sockaddr_ctl *, void **);
110static errno_t rvi_ctl_send(kern_ctl_ref, uint32_t, void *, mbuf_t, int);
111static errno_t rvi_ctl_disconnect(kern_ctl_ref, uint32_t, void *);
112static errno_t rvi_ctl_getopt(kern_ctl_ref, uint32_t, void *, int, void *, size_t *);
113
114int
115rvi_init()
116{
117 int error = 0;
118
119 if ((error = rvi_register_control()) != 0) {
120 os_log(OS_LOG_DEFAULT, "rvi_start failed: rvi_register_control failure");
121 return error;
122 }
123
124 return 0;
125}
126
127static inline void
128rvi_lock_shared(lck_rw_t *mtx)
129{
130 lck_rw_lock_shared(lck: mtx);
131}
132
133static inline void
134rvi_lock_exclusive(lck_rw_t *mtx)
135{
136 lck_rw_lock_exclusive(lck: mtx);
137}
138
139static inline void
140rvi_lock_done_shared(lck_rw_t *mtx)
141{
142 lck_rw_unlock_shared(lck: mtx);
143}
144
145static inline void
146rvi_lock_done_exclusive(lck_rw_t *mtx)
147{
148 lck_rw_unlock_exclusive(lck: mtx);
149}
150
151static errno_t
152rvi_create_if(struct rvi_client_t *client)
153{
154 errno_t err = 0;
155 struct ifnet_init_params rvi_ifinit;
156
157 memset(s: &rvi_ifinit, c: 0x0, n: sizeof(rvi_ifinit));
158 rvi_ifinit.name = RVI_IF_NAME;
159 rvi_ifinit.unit = client->_vif;
160 rvi_ifinit.type = RVI_IF_TYPE;
161 rvi_ifinit.family = RVI_IF_FAMILY;
162 rvi_ifinit.output = rvi_output;
163 rvi_ifinit.demux = rvi_demux;
164 rvi_ifinit.add_proto = rvi_add_proto;
165 rvi_ifinit.del_proto = rvi_del_proto;
166 rvi_ifinit.ioctl = rvi_ioctl;
167 rvi_ifinit.detach = rvi_detach;
168 rvi_ifinit.softc = client;
169
170 err = ifnet_allocate(&rvi_ifinit, &client->_ifp);
171 if (err != 0) {
172 os_log(OS_LOG_DEFAULT, "%s: ifnet_allocate for %s%d failed - %d",
173 __func__, RVI_IF_NAME, client->_vif, err);
174 goto done;
175 }
176
177 ifnet_set_flags(interface: client->_ifp, RVI_IF_FLAGS, RVI_IF_FLAGS);
178
179 err = ifnet_attach(interface: client->_ifp, NULL);
180 if (err != 0) {
181 os_log(OS_LOG_DEFAULT, "%s: ifnet_attach for %s%d failed - %d",
182 __func__, RVI_IF_NAME, client->_vif, err);
183 ifnet_release(interface: client->_ifp);
184 goto done;
185 }
186
187 bpf_attach(interface: client->_ifp, DLT_PKTAP, header_length: sizeof(struct pktap_header), NULL,
188 tap: rvi_set_bpf_tap);
189 bpf_attach(interface: client->_ifp, DLT_RAW, header_length: 0, NULL, tap: rvi_set_bpf_tap);
190done:
191 return err;
192}
193
194static errno_t
195rvi_destroy_if(struct rvi_client_t *client)
196{
197 errno_t err = 0;
198
199 if (client == NULL) {
200 goto done;
201 }
202
203 err = ifnet_detach(interface: client->_ifp);
204 if (err != 0) {
205 os_log(OS_LOG_DEFAULT, "%s: ifnet_detach for %s%d failed - %d",
206 __func__, RVI_IF_NAME, client->_vif, err);
207 }
208done:
209 return err;
210}
211
212static void
213rvi_detach(ifnet_t ifp)
214{
215 struct rvi_client_t *client;
216
217 rvi_lock_exclusive(mtx: &rvi_mtx);
218
219 client = ifnet_softc(interface: ifp);
220 LIST_REMOVE(client, _cle);
221
222 ifnet_release(interface: ifp);
223
224 rvi_lock_done_exclusive(mtx: &rvi_mtx);
225
226 kfree_type(struct rvi_client_t, client);
227}
228
229static void
230rvi_insert_client(struct rvi_client_t *client)
231{
232 struct rvi_client_t *itr = NULL;
233 uint32_t ph = 0;
234
235 rvi_lock_exclusive(mtx: &rvi_mtx);
236
237 if (LIST_EMPTY(&_s_rvi_clients)) {
238 LIST_INSERT_HEAD(&_s_rvi_clients, client, _cle);
239 } else {
240 LIST_FOREACH(itr, &_s_rvi_clients, _cle) {
241 if (ph != itr->_vif) {
242 LIST_INSERT_BEFORE(itr, client, _cle);
243 break;
244 }
245
246 ph++;
247
248 if (LIST_NEXT(itr, _cle) == NULL) {
249 LIST_INSERT_AFTER(itr, client, _cle);
250 break;
251 }
252 }
253 }
254
255 rvi_lock_done_exclusive(mtx: &rvi_mtx);
256
257 client->_vif = ph;
258}
259
260static void
261rvi_remove_client(uint32_t unit)
262{
263 struct rvi_client_t *client = NULL;
264
265 rvi_lock_shared(mtx: &rvi_mtx);
266
267 LIST_FOREACH(client, &_s_rvi_clients, _cle) {
268 if (client->_unit == unit) {
269 break;
270 }
271 }
272
273 rvi_lock_done_shared(mtx: &rvi_mtx);
274
275 if (client == NULL) {
276 panic("rvi_ctl_disconnect: received a disconnect notification without a cache entry");
277 }
278
279 (void)rvi_destroy_if(client);
280}
281
282
283static errno_t
284rvi_register_control(void)
285{
286 errno_t err = 0;
287 struct kern_ctl_reg kern_ctl;
288
289 bzero(s: &kern_ctl, n: sizeof(kern_ctl));
290 strlcpy(dst: kern_ctl.ctl_name, RVI_CONTROL_NAME, n: sizeof(kern_ctl.ctl_name));
291 kern_ctl.ctl_name[sizeof(kern_ctl.ctl_name) - 1] = 0;
292 kern_ctl.ctl_flags = CTL_FLAG_PRIVILEGED;
293 kern_ctl.ctl_sendsize = RVI_BUFFERSZ;
294 kern_ctl.ctl_recvsize = RVI_BUFFERSZ;
295 kern_ctl.ctl_connect = rvi_ctl_connect;
296 kern_ctl.ctl_disconnect = rvi_ctl_disconnect;
297 kern_ctl.ctl_send = rvi_ctl_send;
298 kern_ctl.ctl_setopt = NULL;
299 kern_ctl.ctl_getopt = rvi_ctl_getopt;
300
301 err = ctl_register(userkctl: &kern_ctl, kctlref: &rvi_kernctl);
302
303 return err;
304}
305
306static errno_t
307rvi_ctl_connect(kern_ctl_ref kctlref, struct sockaddr_ctl *sac, void **unitinfo)
308{
309#pragma unused(kctlref)
310 errno_t err = 0;
311 struct rvi_client_t *client = NULL;
312
313 client = kalloc_type(struct rvi_client_t, Z_WAITOK | Z_ZERO | Z_NOFAIL);
314
315 client->_unit = sac->sc_unit;
316 rvi_insert_client(client);
317
318 err = rvi_create_if(client);
319 if (err != 0) {
320 os_log(OS_LOG_DEFAULT, "%s: failure to create virtual interface %d",
321 __func__, err);
322 }
323 *unitinfo = client;
324
325 return err;
326}
327
328static errno_t
329rvi_ctl_disconnect(kern_ctl_ref kctlref, uint32_t unit, void *unitinfo)
330{
331#pragma unused(kctlref)
332#pragma unused(unitinfo)
333 errno_t err = 0;
334
335 rvi_remove_client(unit);
336
337 return err;
338}
339
340static errno_t
341rvi_ctl_getopt(kern_ctl_ref kctlref, uint32_t unit, void *unitinfo,
342 int opt, void *data, size_t *len)
343{
344#pragma unused(kctlref)
345#pragma unused(unit)
346 errno_t err = 0;
347 int n;
348 struct rvi_client_t *client = (struct rvi_client_t *)unitinfo;
349
350 rvi_lock_shared(mtx: &rvi_mtx);
351
352 switch (opt) {
353 case RVI_COMMAND_GET_INTERFACE:
354 if (data == NULL || len == NULL) {
355 err = EINVAL;
356 break;
357 }
358 n = scnprintf(data, count: *len, "%s%u", ifnet_name(interface: client->_ifp),
359 ifnet_unit(interface: client->_ifp));
360
361 *len = n + 1;
362 break;
363
364 case RVI_COMMAND_VERSION:
365 if (data == NULL || len == NULL || *len < sizeof(int)) {
366 err = EINVAL;
367 break;
368 }
369 *(int *)data = RVI_VERSION_CURRENT;
370 *len = sizeof(int);
371 break;
372
373 default:
374 err = ENOPROTOOPT;
375 break;
376 }
377
378 rvi_lock_done_shared(mtx: &rvi_mtx);
379
380 return err;
381}
382
383static errno_t
384rvi_ctl_send(kern_ctl_ref kctlref, uint32_t unit, void *unitinfo, mbuf_t m, int flags)
385{
386#pragma unused(kctlref)
387#pragma unused(unit)
388#pragma unused(flags)
389 errno_t err = 0;
390 struct rvi_client_t *client = (struct rvi_client_t *)unitinfo;
391 struct pktap_header pktap_hdr;
392 uint32_t hdr_length;
393
394 err = mbuf_copydata(mbuf: m, offset: 0, length: sizeof(struct pktap_header), out_data: (void *)&pktap_hdr);
395 if (err != 0) {
396 os_log(OS_LOG_DEFAULT, "%s: mbuf_copydata failed %d", __func__, err);
397 goto done;
398 }
399 hdr_length = pktap_hdr.pth_length;
400
401 mbuf_adj(mbuf: m, len: hdr_length);
402
403 rvi_lock_shared(mtx: &rvi_mtx);
404
405 err = rvi_bpf_tap(client->_ifp, m,
406 pktap_hdr.pth_flags & PTH_FLAG_DIR_OUT ? 1 : 0,
407 client, &pktap_hdr);
408
409 rvi_lock_done_shared(mtx: &rvi_mtx);
410done:
411 mbuf_freem(mbuf: m);
412 return err;
413}
414
415static errno_t
416rvi_output(ifnet_t ifp, mbuf_t m)
417{
418#pragma unused(ifp)
419
420 mbuf_freem(mbuf: m);
421 return 0;
422}
423
424static errno_t
425rvi_demux(ifnet_t ifp, mbuf_t m, char *header, protocol_family_t *ppf)
426{
427#pragma unused(ifp)
428#pragma unused(m)
429#pragma unused(header)
430#pragma unused(ppf)
431
432 return ENOTSUP;
433}
434
435static errno_t
436rvi_add_proto( ifnet_t ifp, protocol_family_t pf,
437 const struct ifnet_demux_desc *dmx, uint32_t cnt)
438{
439#pragma unused(ifp)
440#pragma unused(pf)
441#pragma unused(dmx)
442#pragma unused(cnt)
443
444 return EINVAL;
445}
446
447static errno_t
448rvi_del_proto(ifnet_t ifp, protocol_family_t pf)
449{
450#pragma unused(ifp)
451#pragma unused(pf)
452
453 return EINVAL;
454}
455
456static errno_t
457rvi_ioctl(ifnet_t ifp, unsigned long cmd, void *data)
458{
459#pragma unused(ifp)
460#pragma unused(cmd)
461#pragma unused(data)
462
463 return ENOTSUP;
464}
465
466static errno_t
467rvi_set_bpf_tap(ifnet_t ifp, uint32_t dlt, bpf_tap_mode mode)
468{
469 struct rvi_client_t *client;
470
471 rvi_lock_shared(mtx: &rvi_mtx);
472
473 client = ifnet_softc(interface: ifp);
474 if (client == NULL) {
475 os_log(OS_LOG_DEFAULT, "%s: ifnet_softc is NULL for ifp %p", __func__, ifp);
476 goto done;
477 }
478 switch (dlt) {
479 case DLT_RAW:
480 if (mode == 0) {
481 if (client->_raw_count > 0) {
482 client->_raw_count--;
483 }
484 } else {
485 client->_raw_count++;
486 }
487 break;
488 case DLT_PKTAP:
489 if (mode == 0) {
490 if (client->_pktap_count > 0) {
491 client->_pktap_count--;
492 }
493 } else {
494 client->_pktap_count++;
495 }
496 break;
497 }
498done:
499 rvi_lock_done_shared(mtx: &rvi_mtx);
500
501 return 0;
502}
503
504/*
505 * Note: called with the rvi lock taken as shared
506 */
507static errno_t
508rvi_bpf_tap(ifnet_t ifp, mbuf_t m, int outgoing, struct rvi_client_t *client,
509 struct pktap_header *pktap_hdr)
510{
511#pragma unused(ifp)
512 errno_t err = 0;
513 void (*bpf_tap_fn)(ifnet_t, uint32_t, mbuf_t, void *, size_t ) =
514 outgoing ? bpf_tap_out : bpf_tap_in;
515
516 if (client->_pktap_count > 0) {
517 bpf_tap_fn(client->_ifp, DLT_PKTAP, m, pktap_hdr,
518 sizeof(struct pktap_header));
519 }
520
521 if (client->_raw_count > 0 &&
522 (pktap_hdr->pth_protocol_family == AF_INET ||
523 pktap_hdr->pth_protocol_family == AF_INET6)) {
524 /*
525 * We can play just with the length of the first mbuf in the
526 * chain because bpf_tap_imp() disregard the packet length
527 * of the mbuf packet header.
528 */
529 if (pktap_hdr->pth_frame_pre_length > mbuf_len(mbuf: m)) {
530 err = mbuf_pullup(mbuf: &m, len: pktap_hdr->pth_frame_pre_length);
531 if (err != 0) {
532 os_log(OS_LOG_DEFAULT, "%s mbuf_pullup failed", __func__);
533 return 0;
534 }
535 }
536
537 if (mbuf_setdata(mbuf: m, data: m_mtod_current(m) + pktap_hdr->pth_frame_pre_length,
538 len: m->m_len - pktap_hdr->pth_frame_pre_length) == 0) {
539 bpf_tap_fn(client->_ifp, DLT_RAW, m, NULL, 0);
540 mbuf_setdata(mbuf: m, data: m_mtod_current(m) - pktap_hdr->pth_frame_pre_length,
541 len: m->m_len + pktap_hdr->pth_frame_pre_length);
542 }
543 }
544
545 return err;
546}
547