xref: /minix3/sys/arch/i386/stand/lib/test/ether_bpf.c (revision 58a2b0008e28f606a7f7f5faaeaba4faac57a1ea)
1 /*	$NetBSD: ether_bpf.c,v 1.10 2008/12/14 18:46:33 christos Exp $	*/
2 
3 /*
4  * Copyright (c) 1998
5  *	Matthias Drochner.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  *
27  */
28 
29 #include "sanamespace.h"
30 
31 #include <stdio.h>
32 #include <fcntl.h>
33 #include <unistd.h>
34 #include <stdlib.h>
35 #include <limits.h>
36 #include <sys/ioctl.h>
37 #include <sys/queue.h>
38 #include <sys/socket.h>
39 #include <net/if.h>
40 #include <net/bpf.h>
41 #include <net/if_dl.h>
42 #include <netinet/in.h>
43 #include <kvm.h>
44 #include <nlist.h>
45 #include <string.h>
46 #include <err.h>
47 #include <errno.h>
48 
49 #include <netif/netif_small.h>
50 #include <netif/etherdrv.h>
51 
52 #define BPFDEV "/dev/bpf0"
53 
54 #define MAXPKT 1536
55 
56 /*
57  * Allows to use any configured interface with
58  * standalone network code. Provides the interface used
59  * by i386/stand/lib/netif/netif_small.c.
60  */
61 
62 static int bpf = -1;
63 
64 static struct nlist nl[] = {
65 	{"_ifnet"},
66 	{NULL}
67 };
68 
69 int
EtherInit(char * ha)70 EtherInit(char *ha)
71 {
72 	int res;
73 	u_int val;
74 	struct ifreq ifr;
75 	kvm_t *kvm;
76 	char errbuf[_POSIX2_LINE_MAX];
77 	struct ifnet_head ifh;
78 	struct ifnet *ifp;
79 	struct ifaddr *ifap = 0;
80 	struct sockaddr_dl *sdlp;
81 	int sdllen;
82 
83 	bpf = open(BPFDEV, O_RDWR, 0);
84 	if (bpf < 0) {
85 		warn("open %s", BPFDEV);
86 		return 0;
87 	}
88 
89 	val = MAXPKT;
90 	res = ioctl(bpf, BIOCSBLEN, &val);
91 	if (res < 0) {
92 		warn("ioctl BIOCSBLEN");
93 		return 0;
94 	}
95 
96 	val = 1;
97 	res = ioctl(bpf, BIOCIMMEDIATE, &val);
98 	if (res < 0) {
99 		warn("ioctl BIOCIMMEDIATE");
100 		return 0;
101 	}
102 
103 	val = 1;
104 	res = ioctl(bpf, FIONBIO, &val);
105 	if (res < 0) {
106 		warn("ioctl FIONBIO");
107 		return 0;
108 	}
109 
110 	memcpy(ifr.ifr_name, BPF_IFNAME, IFNAMSIZ);
111 	res = ioctl(bpf, BIOCSETIF, &ifr);
112 	if (res < 0) {
113 		warn("ioctl BIOCSETIF %s", BPF_IFNAME);
114 		return 0;
115 	}
116 
117 	kvm = kvm_openfiles(0, 0, 0, O_RDONLY, errbuf);
118 	if (!kvm) {
119 		warnx(errbuf);
120 		return 0;
121 	}
122 	if (kvm_nlist(kvm, nl) < 0) {
123 		warnx("nlist failed (%s)", kvm_geterr(kvm));
124 		kvm_close(kvm);
125 		return 0;
126 	}
127 
128 	kvm_read(kvm, nl[0].n_value, &ifh, sizeof(struct ifnet_head));
129 	ifp = TAILQ_FIRST(&ifh);
130 	while (ifp) {
131 		struct ifnet ifnet;
132 		kvm_read(kvm, (u_long)ifp, &ifnet, sizeof(struct ifnet));
133 		if (!strcmp(ifnet.if_xname, BPF_IFNAME)) {
134 			ifap = IFADDR_FIRST(&ifnet);
135 			break;
136 		}
137 		ifp = IFNET_NEXT(&ifnet);
138 	}
139 	if (!ifp) {
140 		warnx("interface not found");
141 		kvm_close(kvm);
142 		return 0;
143 	}
144 
145 #define _offsetof(t, m) ((int)((void *)&((t *)0)->m))
146 	sdllen = _offsetof(struct sockaddr_dl,
147 			   sdl_data[0]) + strlen(BPF_IFNAME) + 6;
148 	sdlp = malloc(sdllen);
149 
150 	while (ifap) {
151 		struct ifaddr ifaddr;
152 		kvm_read(kvm, (u_long)ifap, &ifaddr, sizeof(struct ifaddr));
153 		kvm_read(kvm, (u_long)ifaddr.ifa_addr, sdlp, sdllen);
154 		if (sdlp->sdl_family == AF_LINK) {
155 			memcpy(ha, CLLADDR(sdlp), 6);
156 			break;
157 		}
158 		ifap = IFADDR_NEXT(&ifaddr);
159 	}
160 	free(sdlp);
161 	kvm_close(kvm);
162 	if (!ifap) {
163 		warnx("interface hw addr not found");
164 		return 0;
165 	}
166 	return 1;
167 }
168 
169 void
EtherStop(void)170 EtherStop(void)
171 {
172 
173 	if (bpf != -1)
174 		close(bpf);
175 }
176 
177 int
EtherSend(char * pkt,int len)178 EtherSend(char *pkt, int len)
179 {
180 
181 	if (write(bpf, pkt, len) != len) {
182 		warn("EtherSend");
183 		return -1;
184 	}
185 	return len;
186 }
187 
188 static union {
189 	struct bpf_hdr h;
190 	u_char buf[MAXPKT];
191 } rbuf;
192 
193 int
EtherReceive(char * pkt,int maxlen)194 EtherReceive(char *pkt, int maxlen)
195 {
196 	int res;
197 
198 	res = read(bpf, &rbuf, MAXPKT);
199 	if (res > 0) {
200 #if 0
201 		int i;
202 		fprintf(stderr, "got packet, len=%d\n", rbuf.h.bh_caplen);
203 		if (rbuf.h.bh_caplen < rbuf.h.bh_datalen)
204 			printf("(truncated)\n");
205 		for (i = 0; i < 20; i++)
206 			fprintf(stderr, "%02x ", rbuf.buf[rbuf.h.bh_hdrlen + i]);
207 		fprintf(stderr, "\n");
208 #endif
209 		if (rbuf.h.bh_caplen > maxlen)
210 			return 0;
211 		memcpy(pkt, &rbuf.buf[rbuf.h.bh_hdrlen], rbuf.h.bh_caplen);
212 		return rbuf.h.bh_caplen;
213 	}
214 
215 	return 0;
216 }
217