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, ©); 193 if (copy == NULL) 194 continue; 195 196 err = mbuf_prepend(©, 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 438