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