]> git.saurik.com Git - apple/xnu.git/blame - bsd/net/iptap.c
xnu-2050.7.9.tar.gz
[apple/xnu.git] / bsd / net / iptap.c
CommitLineData
316670eb
A
1/*
2 * Copyright (c) 1999-2010 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#include <string.h>
29#include <stdint.h>
30#include <stdbool.h>
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>
41#include <sys/mbuf.h>
42#include <net/if_types.h>
43#include <net/if.h>
44#include <net/kpi_interface.h>
45#include <net/bpf.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>
51
52#include <IOKit/IOLib.h>
53
54#define IPTAP_IF_NAME "iptap"
55#define IPTAP_PRINTF printf
56#define IP_TAP_NOT_USED 0
57
58#define VALID_PACKET(type, label)\
59 if (iptap_clients == 0) \
60 goto label; \
61 \
62 if (type != IFT_ETHER && \
63 type != IFT_CELLULAR) \
64 goto label
65
66static void *iptap_alloc(size_t);
67static void iptap_free(void *);
68static errno_t iptap_register_control(void);
69static inline void iptap_lock_shared(void);
70static inline void iptap_lock_exclusive(void);
71static inline void iptap_lock_done(void);
72static void iptap_alloc_lock(void);
73static void iptap_free_lock(void);
74
75static void iptap_enqueue_mbuf(struct ifnet *, protocol_family_t, struct mbuf *, u_int32_t, u_int32_t, u_int8_t);
76
77/* kernctl callbacks */
78static errno_t iptap_ctl_connect(kern_ctl_ref, struct sockaddr_ctl *, void **);
79static errno_t iptap_ctl_disconnect(kern_ctl_ref, u_int32_t, void *);
80
81#if IP_TAP_NOT_USED
82
83static errno_t iptap_deregister_control(void);
84
85static errno_t iptap_ctl_send(kern_ctl_ref, u_int32_t, void *, mbuf_t, int);
86static errno_t iptap_ctl_setopt(kern_ctl_ref, u_int32_t, void *, int, void *, size_t);
87static errno_t iptap_ctl_getopt(kern_ctl_ref, u_int32_t, void *, int, void *, size_t *);
88
89#endif /* IP_TAP_NOT_USED */
90
91decl_lck_rw_data(static, iptap_mtx);
92static lck_grp_t *iptap_grp;
93static kern_ctl_ref iptap_kernctl;
94static unsigned int iptap_clients;
95static OSMallocTag iptap_malloc_tag;
96
97struct iptap_client_t {
98 LIST_ENTRY(iptap_client_t) _cle;
99 u_int32_t _unit;
100};
101
102static LIST_HEAD(, iptap_client_t) _s_iptap_clients;
103
104
105__private_extern__ void
106iptap_init(void) {
107
108 iptap_alloc_lock();
109
110 iptap_malloc_tag = OSMalloc_Tagalloc(IPTAP_CONTROL_NAME, OSMT_DEFAULT);
111 if (iptap_malloc_tag == NULL) {
112 iptap_free_lock();
113 IPTAP_PRINTF("iptap_init failed: unable to allocate malloc tag.\n");
114 return;
115 }
116
117 if (iptap_register_control() != 0) {
118 iptap_free_lock();
119 OSMalloc_Tagfree(iptap_malloc_tag);
120 IPTAP_PRINTF("iptap_init failed: iptap_register_control failure.\n");
121 return;
122 }
123
124 iptap_clients = 0;
125}
126
127__private_extern__ void
128iptap_ipf_input(struct ifnet *ifp, protocol_family_t proto, struct mbuf *mp, char *frame_header)
129{
130 VALID_PACKET(ifp->if_type, done);
131
132 do {
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;
136
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);
141 }
142 } else {
143 iptap_enqueue_mbuf(ifp, proto, mp, 0, 0, IPTAP_INPUT_TAG);
144 }
145
146 } while (0);
147
148done:
149 return;
150}
151
152__private_extern__ void
153iptap_ipf_output(struct ifnet *ifp, protocol_family_t proto, struct mbuf *mp, u_int32_t pre, u_int32_t post)
154{
155 VALID_PACKET(ifp->if_type, done);
156
157 iptap_enqueue_mbuf(ifp, proto, mp, pre, post, IPTAP_OUTPUT_TAG);
158
159done:
160 return;
161}
162
163static void
164iptap_enqueue_mbuf(struct ifnet *ifp, protocol_family_t proto, struct mbuf *mp, u_int32_t pre, u_int32_t post, u_int8_t io)
165{
166 errno_t err = 0;
167 struct iptap_client_t *client = NULL;
168 mbuf_t copy, itr = (mbuf_t)mp;
169 iptap_hdr_t header;
170 u_int32_t len = 0;
171
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;
181 header.io = io;
182
183 do {
184 len += mbuf_len(itr);
185 itr = mbuf_next(itr);
186 } while (itr != NULL);
187
188 iptap_lock_shared();
189
190 LIST_FOREACH(client, &_s_iptap_clients, _cle) {
191
192 mbuf_dup((mbuf_t)mp, MBUF_DONTWAIT, &copy);
193 if (copy == NULL)
194 continue;
195
196 err = mbuf_prepend(&copy, sizeof(header), MBUF_DONTWAIT);
197 if (err != 0) {
198 if (copy != NULL) {
199 mbuf_freem(copy);
200 copy = NULL;
201 }
202 continue;
203 }
204
205 HTONS(header.unit);
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);
211
212 memcpy(mbuf_data(copy), &header, sizeof(header));
213
214 err = ctl_enqueuembuf(iptap_kernctl, client->_unit, copy, CTL_DATA_EOR);
215 if (err != 0) {
216 mbuf_freem(copy);
217 copy = NULL;
218 IPTAP_PRINTF("iptap_enqueue_mbuf failed: %d\n", (err));
219 continue;
220 }
221 }
222
223 iptap_lock_done();
224}
225
226static void*
227iptap_alloc(size_t size)
228{
229 size_t *mem = OSMalloc(size + sizeof(size_t), iptap_malloc_tag);
230
231 if (mem) {
232 *mem = size + sizeof(size_t);
233 mem++;
234 memset(mem, 0x0, size);
235 }
236
237 return (void*)mem;
238}
239
240static void
241iptap_free(void *ptr)
242{
243 size_t *size = ptr;
244 size--;
245 OSFree(size, *size, iptap_malloc_tag);
246 ptr = NULL;
247}
248
249static void
250iptap_alloc_lock(void)
251{
252 lck_grp_attr_t *grp_attr;
253 lck_attr_t *attr;
254
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);
259
260 attr = lck_attr_alloc_init();
261 lck_attr_setdefault(attr);
262
263 lck_rw_init(&iptap_mtx, iptap_grp, attr);
264 lck_attr_free(attr);
265}
266
267static void
268iptap_free_lock(void)
269{
270 lck_rw_destroy(&iptap_mtx, iptap_grp);
271 lck_grp_free(iptap_grp);
272 iptap_grp = NULL;
273}
274
275static inline void
276iptap_lock_shared(void)
277{
278 lck_rw_lock_shared(&iptap_mtx);
279}
280
281static inline void
282iptap_lock_exclusive(void)
283{
284 lck_rw_lock_exclusive(&iptap_mtx);
285}
286
287static inline void
288iptap_lock_done(void)
289{
290 lck_rw_done(&iptap_mtx);
291}
292
293static errno_t
294iptap_register_control(void)
295{
296 errno_t err = 0;
297 struct kern_ctl_reg kern_ctl;
298
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;
309
310 err = ctl_register(&kern_ctl, &iptap_kernctl);
311
312 return (err);
313}
314
315static errno_t
316iptap_ctl_connect(kern_ctl_ref kctlref, struct sockaddr_ctl *sac, void **unitinfo)
317{
318#pragma unused(kctlref)
319#pragma unused(unitinfo)
320 errno_t err = 0;
321 struct iptap_client_t *client = NULL;
322
323 client = (struct iptap_client_t *)iptap_alloc(sizeof(struct iptap_client_t));
324 if (client != NULL) {
325 iptap_lock_exclusive();
326
327 iptap_clients++;
328 client->_unit = sac->sc_unit;
329 LIST_INSERT_HEAD(&_s_iptap_clients, client, _cle);
330
331 iptap_lock_done();
332 } else {
333 err = ENOMEM;
334 }
335
336 return (err == 0) ? (0) : (err);
337}
338
339static errno_t
340iptap_ctl_disconnect(kern_ctl_ref kctlref, u_int32_t unit, void *unitinfo)
341{
342#pragma unused(kctlref)
343#pragma unused(unitinfo)
344 errno_t err = 0;
345 struct iptap_client_t *client = NULL;
346
347 iptap_lock_exclusive();
348
349 LIST_FOREACH(client, &_s_iptap_clients, _cle) {
350 if (client->_unit == unit) {
351 iptap_clients--;
352 LIST_REMOVE(client, _cle);
353 break;
354 }
355 }
356
357 iptap_lock_done();
358
359 /* get rid of all the interfaces before free'ing */
360 iptap_free(client);
361
362 if (client == NULL)
363 panic("iptap_ctl_disconnect: received a disconnect notification without a cache entry.\n");
364
365 return (err == 0) ? (0) : (err);
366}
367
368#if IP_TAP_NOT_USED
369
370__private_extern__ void
371iptap_destroy(void) {
372
373 if (iptap_clients != 0) {
374 IPTAP_PRINTF("iptap_destroy failed: there are still outstanding clients.\n");
375 return;
376 }
377
378 if (iptap_deregister_control() != 0) {
379 IPTAP_PRINTF("iptap_destroy failed: iptap_deregister_control failed.\n");
380 }
381
382 OSMalloc_Tagfree(iptap_malloc_tag);
383
384 iptap_free_lock();
385}
386
387static errno_t
388iptap_deregister_control(void)
389{
390 errno_t err = 0;
391
392 if (iptap_kernctl != NULL) {
393 err = ctl_deregister(iptap_kernctl);
394 } else {
395 err = EINVAL;
396 }
397
398 return (err);
399}
400
401static errno_t
402iptap_ctl_send(kern_ctl_ref kctlref, u_int32_t unit, void *unitinfo, mbuf_t m, int flags)
403{
404#pragma unused(kctlref)
405#pragma unused(unit)
406#pragma unused(unitinfo)
407#pragma unused(m)
408#pragma unused(flags)
409 return (KERN_SUCCESS);
410}
411
412static errno_t
413iptap_ctl_setopt(kern_ctl_ref kctlref, u_int32_t unit, void *unitinfo, int opt, void *data, size_t len)
414{
415#pragma unused(kctlref)
416#pragma unused(unit)
417#pragma unused(unitinfo)
418#pragma unused(opt)
419#pragma unused(data)
420#pragma unused(len)
421 return (KERN_SUCCESS);
422}
423
424static errno_t
425iptap_ctl_getopt(kern_ctl_ref kctlref, u_int32_t unit, void *unitinfo, int opt, void *data, size_t *len)
426{
427#pragma unused(kctlref)
428#pragma unused(unit)
429#pragma unused(unitinfo)
430#pragma unused(opt)
431#pragma unused(data)
432#pragma unused(len)
433 return (KERN_SUCCESS);
434}
435
436#endif /* IP_TAP_NOT_USED */
437