2 * Copyright (c) 1999-2010 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
31 #include <mach/mach_types.h>
32 #include <kern/locks.h>
33 #include <sys/kernel.h>
34 #include <sys/param.h>
35 #include <sys/sockio.h>
36 #include <sys/socket.h>
37 #include <sys/queue.h>
38 #include <sys/cdefs.h>
39 #include <sys/kern_control.h>
40 #include <sys/uio_internal.h>
42 #include <net/if_types.h>
44 #include <net/kpi_interface.h>
46 #include <net/iptap.h>
47 #include <netinet/kpi_ipfilter.h>
48 #include <libkern/libkern.h>
49 #include <libkern/OSMalloc.h>
50 #include <libkern/OSAtomic.h>
52 #include <IOKit/IOLib.h>
54 #define IPTAP_IF_NAME "iptap"
55 #define IPTAP_PRINTF printf
56 #define IP_TAP_NOT_USED 0
58 #define VALID_PACKET(type, label)\
59 if (iptap_clients == 0) \
62 if (type != IFT_ETHER && \
63 type != IFT_CELLULAR) \
66 static void *iptap_alloc(size_t);
67 static void iptap_free(void *);
68 static errno_t
iptap_register_control(void);
69 static inline void iptap_lock_shared(void);
70 static inline void iptap_lock_exclusive(void);
71 static inline void iptap_lock_done(void);
72 static void iptap_alloc_lock(void);
73 static void iptap_free_lock(void);
75 static void iptap_enqueue_mbuf(struct ifnet
*, protocol_family_t
, struct mbuf
*, u_int32_t
, u_int32_t
, u_int8_t
);
77 /* kernctl callbacks */
78 static errno_t
iptap_ctl_connect(kern_ctl_ref
, struct sockaddr_ctl
*, void **);
79 static errno_t
iptap_ctl_disconnect(kern_ctl_ref
, u_int32_t
, void *);
83 static errno_t
iptap_deregister_control(void);
85 static errno_t
iptap_ctl_send(kern_ctl_ref
, u_int32_t
, void *, mbuf_t
, int);
86 static errno_t
iptap_ctl_setopt(kern_ctl_ref
, u_int32_t
, void *, int, void *, size_t);
87 static errno_t
iptap_ctl_getopt(kern_ctl_ref
, u_int32_t
, void *, int, void *, size_t *);
89 #endif /* IP_TAP_NOT_USED */
91 decl_lck_rw_data(static, iptap_mtx
);
92 static lck_grp_t
*iptap_grp
;
93 static kern_ctl_ref iptap_kernctl
;
94 static unsigned int iptap_clients
;
95 static OSMallocTag iptap_malloc_tag
;
97 struct iptap_client_t
{
98 LIST_ENTRY(iptap_client_t
) _cle
;
102 static LIST_HEAD(, iptap_client_t
) _s_iptap_clients
;
105 __private_extern__
void
110 iptap_malloc_tag
= OSMalloc_Tagalloc(IPTAP_CONTROL_NAME
, OSMT_DEFAULT
);
111 if (iptap_malloc_tag
== NULL
) {
113 IPTAP_PRINTF("iptap_init failed: unable to allocate malloc tag.\n");
117 if (iptap_register_control() != 0) {
119 OSMalloc_Tagfree(iptap_malloc_tag
);
120 IPTAP_PRINTF("iptap_init failed: iptap_register_control failure.\n");
127 __private_extern__
void
128 iptap_ipf_input(struct ifnet
*ifp
, protocol_family_t proto
, struct mbuf
*mp
, char *frame_header
)
130 VALID_PACKET(ifp
->if_type
, done
);
133 char *hdr
= (char *)mbuf_data(mp
);
134 size_t start
= (size_t)((char*)mbuf_datastart(mp
));
135 size_t o_len
= mp
->m_len
;
137 if (frame_header
!= NULL
&& (size_t)frame_header
>= start
&& (size_t)frame_header
<= (size_t)hdr
) {
138 if (mbuf_setdata(mp
, frame_header
, o_len
+ ((size_t)hdr
- (size_t)frame_header
)) == 0) {
139 iptap_enqueue_mbuf(ifp
, proto
, mp
, ((size_t)hdr
- (size_t)frame_header
), 0, IPTAP_INPUT_TAG
);
140 mbuf_setdata(mp
, hdr
, o_len
);
143 iptap_enqueue_mbuf(ifp
, proto
, mp
, 0, 0, IPTAP_INPUT_TAG
);
152 __private_extern__
void
153 iptap_ipf_output(struct ifnet
*ifp
, protocol_family_t proto
, struct mbuf
*mp
, u_int32_t pre
, u_int32_t post
)
155 VALID_PACKET(ifp
->if_type
, done
);
157 iptap_enqueue_mbuf(ifp
, proto
, mp
, pre
, post
, IPTAP_OUTPUT_TAG
);
164 iptap_enqueue_mbuf(struct ifnet
*ifp
, protocol_family_t proto
, struct mbuf
*mp
, u_int32_t pre
, u_int32_t post
, u_int8_t io
)
167 struct iptap_client_t
*client
= NULL
;
168 mbuf_t copy
, itr
= (mbuf_t
)mp
;
172 memset(&header
, 0x0, sizeof(header
));
173 header
.version
= IPTAP_VERSION_1
;
174 header
.type
= ifp
->if_type
;
175 header
.unit
= ifp
->if_unit
;
176 strlcpy(header
.if_name
, ifp
->if_name
, sizeof(header
.if_name
));
177 header
.hdr_length
= sizeof(header
);
178 header
.protocol_family
= proto
;
179 header
.frame_pre_length
= pre
;
180 header
.frame_pst_length
= post
;
184 len
+= mbuf_len(itr
);
185 itr
= mbuf_next(itr
);
186 } while (itr
!= NULL
);
190 LIST_FOREACH(client
, &_s_iptap_clients
, _cle
) {
192 mbuf_dup((mbuf_t
)mp
, MBUF_DONTWAIT
, ©
);
196 err
= mbuf_prepend(©
, sizeof(header
), MBUF_DONTWAIT
);
206 HTONL(header
.hdr_length
);
207 HTONL(header
.protocol_family
);
208 HTONL(header
.frame_pre_length
);
209 HTONL(header
.frame_pst_length
);
210 header
.length
= htonl(len
);
212 memcpy(mbuf_data(copy
), &header
, sizeof(header
));
214 err
= ctl_enqueuembuf(iptap_kernctl
, client
->_unit
, copy
, CTL_DATA_EOR
);
218 IPTAP_PRINTF("iptap_enqueue_mbuf failed: %d\n", (err
));
227 iptap_alloc(size_t size
)
229 size_t *mem
= OSMalloc(size
+ sizeof(size_t), iptap_malloc_tag
);
232 *mem
= size
+ sizeof(size_t);
234 memset(mem
, 0x0, size
);
241 iptap_free(void *ptr
)
245 OSFree(size
, *size
, iptap_malloc_tag
);
250 iptap_alloc_lock(void)
252 lck_grp_attr_t
*grp_attr
;
255 grp_attr
= lck_grp_attr_alloc_init();
256 lck_grp_attr_setdefault(grp_attr
);
257 iptap_grp
= lck_grp_alloc_init(IPTAP_IF_NAME
, grp_attr
);
258 lck_grp_attr_free(grp_attr
);
260 attr
= lck_attr_alloc_init();
261 lck_attr_setdefault(attr
);
263 lck_rw_init(&iptap_mtx
, iptap_grp
, attr
);
268 iptap_free_lock(void)
270 lck_rw_destroy(&iptap_mtx
, iptap_grp
);
271 lck_grp_free(iptap_grp
);
276 iptap_lock_shared(void)
278 lck_rw_lock_shared(&iptap_mtx
);
282 iptap_lock_exclusive(void)
284 lck_rw_lock_exclusive(&iptap_mtx
);
288 iptap_lock_done(void)
290 lck_rw_done(&iptap_mtx
);
294 iptap_register_control(void)
297 struct kern_ctl_reg kern_ctl
;
299 bzero(&kern_ctl
, sizeof(kern_ctl
));
300 strlcpy(kern_ctl
.ctl_name
, IPTAP_CONTROL_NAME
, sizeof(kern_ctl
.ctl_name
));
301 kern_ctl
.ctl_name
[sizeof(kern_ctl
.ctl_name
) - 1] = 0;
302 kern_ctl
.ctl_flags
= CTL_FLAG_PRIVILEGED
;
303 kern_ctl
.ctl_recvsize
= IPTAP_BUFFERSZ
;
304 kern_ctl
.ctl_connect
= iptap_ctl_connect
;
305 kern_ctl
.ctl_disconnect
= iptap_ctl_disconnect
;
306 kern_ctl
.ctl_send
= NULL
;
307 kern_ctl
.ctl_setopt
= NULL
;
308 kern_ctl
.ctl_getopt
= NULL
;
310 err
= ctl_register(&kern_ctl
, &iptap_kernctl
);
316 iptap_ctl_connect(kern_ctl_ref kctlref
, struct sockaddr_ctl
*sac
, void **unitinfo
)
318 #pragma unused(kctlref)
319 #pragma unused(unitinfo)
321 struct iptap_client_t
*client
= NULL
;
323 client
= (struct iptap_client_t
*)iptap_alloc(sizeof(struct iptap_client_t
));
324 if (client
!= NULL
) {
325 iptap_lock_exclusive();
328 client
->_unit
= sac
->sc_unit
;
329 LIST_INSERT_HEAD(&_s_iptap_clients
, client
, _cle
);
336 return (err
== 0) ? (0) : (err
);
340 iptap_ctl_disconnect(kern_ctl_ref kctlref
, u_int32_t unit
, void *unitinfo
)
342 #pragma unused(kctlref)
343 #pragma unused(unitinfo)
345 struct iptap_client_t
*client
= NULL
;
347 iptap_lock_exclusive();
349 LIST_FOREACH(client
, &_s_iptap_clients
, _cle
) {
350 if (client
->_unit
== unit
) {
352 LIST_REMOVE(client
, _cle
);
359 /* get rid of all the interfaces before free'ing */
363 panic("iptap_ctl_disconnect: received a disconnect notification without a cache entry.\n");
365 return (err
== 0) ? (0) : (err
);
370 __private_extern__
void
371 iptap_destroy(void) {
373 if (iptap_clients
!= 0) {
374 IPTAP_PRINTF("iptap_destroy failed: there are still outstanding clients.\n");
378 if (iptap_deregister_control() != 0) {
379 IPTAP_PRINTF("iptap_destroy failed: iptap_deregister_control failed.\n");
382 OSMalloc_Tagfree(iptap_malloc_tag
);
388 iptap_deregister_control(void)
392 if (iptap_kernctl
!= NULL
) {
393 err
= ctl_deregister(iptap_kernctl
);
402 iptap_ctl_send(kern_ctl_ref kctlref
, u_int32_t unit
, void *unitinfo
, mbuf_t m
, int flags
)
404 #pragma unused(kctlref)
406 #pragma unused(unitinfo)
408 #pragma unused(flags)
409 return (KERN_SUCCESS
);
413 iptap_ctl_setopt(kern_ctl_ref kctlref
, u_int32_t unit
, void *unitinfo
, int opt
, void *data
, size_t len
)
415 #pragma unused(kctlref)
417 #pragma unused(unitinfo)
421 return (KERN_SUCCESS
);
425 iptap_ctl_getopt(kern_ctl_ref kctlref
, u_int32_t unit
, void *unitinfo
, int opt
, void *data
, size_t *len
)
427 #pragma unused(kctlref)
429 #pragma unused(unitinfo)
433 return (KERN_SUCCESS
);
436 #endif /* IP_TAP_NOT_USED */