1/* 2 * Copyright (c) 2000-2012 Apple Inc. All rights reserved. 3 * 4 * @APPLE_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. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24#include <stdlib.h> 25#include <unistd.h> 26#include <stdio.h> 27#include <sys/types.h> 28#include <sys/time.h> 29#include <sys/ioctl.h> 30#include <sys/stat.h> 31#include <fcntl.h> 32#include <net/bpf.h> 33#include <string.h> 34#include <sys/socket.h> 35#include <errno.h> 36#include <net/if.h> 37#include <stdbool.h> 38 39#include "bpflib.h" 40 41#ifdef TESTING 42#include "util.h" 43#endif /* TESTING */ 44 45int 46bpf_set_timeout(int fd, struct timeval * tv_p) 47{ 48 return (ioctl(fd, BIOCSRTIMEOUT, tv_p)); 49} 50 51int 52bpf_get_blen(int fd, int * blen) 53{ 54 return(ioctl(fd, BIOCGBLEN, blen)); 55} 56 57int 58bpf_dispose(int bpf_fd) 59{ 60 if (bpf_fd >= 0) 61 return (close(bpf_fd)); 62 return (0); 63} 64 65int 66bpf_new() 67{ 68 char bpfdev[256]; 69 int i; 70 int fd = -1; 71 72 for (i = 0; true; i++) { 73 snprintf(bpfdev, sizeof(bpfdev), "/dev/bpf%d", i); 74 fd = open(bpfdev, O_RDWR , 0); 75 if (fd >= 0) { 76#ifdef SO_TC_CTL 77 int tc = SO_TC_CTL; 78 (void) ioctl(fd, BIOCSETTC, &tc); 79#endif /* SO_TC_CTL */ 80 break; 81 } 82 if (errno != EBUSY) { 83 break; 84 } 85 } 86 return (fd); 87} 88 89int 90bpf_setif(int fd, const char * en_name) 91{ 92 struct ifreq ifr; 93 94 strlcpy(ifr.ifr_name, en_name, sizeof(ifr.ifr_name)); 95 return (ioctl(fd, BIOCSETIF, &ifr)); 96} 97 98int 99bpf_set_immediate(int fd, u_int value) 100{ 101 return (ioctl(fd, BIOCIMMEDIATE, &value)); 102} 103 104int 105bpf_filter_receive_none(int fd) 106{ 107 struct bpf_insn insns[] = { 108 BPF_STMT(BPF_RET+BPF_K, 0), 109 }; 110 struct bpf_program prog; 111 112 prog.bf_len = sizeof(insns) / sizeof(struct bpf_insn); 113 prog.bf_insns = insns; 114 return ioctl(fd, BIOCSETF, &prog); 115} 116 117int 118bpf_arp_filter(int fd, int type_offset, int type, int pkt_size) 119{ 120 struct bpf_insn insns[] = { 121 BPF_STMT(BPF_LD+BPF_H+BPF_ABS, type_offset), 122 BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, type, 0, 1), 123 BPF_STMT(BPF_RET+BPF_K, pkt_size), 124 BPF_STMT(BPF_RET+BPF_K, 0), 125 }; 126 struct bpf_program prog; 127 128 prog.bf_len = sizeof(insns) / sizeof(struct bpf_insn); 129 prog.bf_insns = insns; 130 return ioctl(fd, BIOCSETF, &prog); 131} 132 133int 134bpf_write(int fd, void * pkt, int len) 135{ 136 return (write(fd, pkt, len)); 137} 138 139#ifdef TESTING 140#include <net/if_arp.h> 141#include <net/ethernet.h> 142#include <netinet/if_ether.h> 143 144 145void 146bpf_read_continuously(int fd, u_int blen) 147{ 148 int n; 149 char * rxbuf = malloc(blen); 150 151 printf("rx buf len is %d\n", blen); 152 while (1) { 153 n = read(fd, rxbuf, blen); 154 if (n < 0) { 155 perror("bpf_read_continuously"); 156 return; 157 } 158 if (n == 0) 159 continue; 160 print_data(rxbuf, n); 161 } 162} 163 164int 165main(int argc, char * argv[]) 166{ 167 int fd = bpf_new(); 168 char * en_name = "en0"; 169 u_int bpf_blen = 0; 170 171 if (fd < 0) { 172 perror("no bpf devices"); 173 exit(1); 174 } 175 176 if (argc > 1) 177 en_name = argv[1]; 178 (void)bpf_set_immediate(fd, 1); 179 if (bpf_arp_filter(fd, 12, ETHERTYPE_ARP, 180 sizeof(struct ether_arp) + sizeof(struct ether_header)) 181 < 0) { 182 perror("bpf_arp_filter"); 183 } 184 if (bpf_setif(fd, en_name) < 0) { 185 perror("bpf_attach"); 186 exit(1); 187 } 188 189 if (bpf_get_blen(fd, &bpf_blen) < 0) { 190 perror("bpf_get_blen"); 191 exit(1); 192 } 193 bpf_read_continuously(fd, bpf_blen); 194 exit(0); 195 return (0); 196} 197#endif /* TESTING */ 198