]> git.saurik.com Git - apple/network_cmds.git/blob - rbootd.tproj/bpf.c
ed214808e42b9af421bbdf280e7e6ec2d4ee1e11
[apple/network_cmds.git] / rbootd.tproj / bpf.c
1 /*
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7 * Reserved. This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 1.0 (the 'License'). You may not use this file
10 * except in compliance with the License. Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
12 * this file.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19 * License for the specific language governing rights and limitations
20 * under the License."
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24 /*
25 * Copyright (c) 1988, 1992 The University of Utah and the Center
26 * for Software Science (CSS).
27 * Copyright (c) 1992, 1993
28 * The Regents of the University of California. All rights reserved.
29 *
30 * This code is derived from software contributed to Berkeley by
31 * the Center for Software Science of the University of Utah Computer
32 * Science Department. CSS requests users of this software to return
33 * to css-dist@cs.utah.edu any improvements that they make and grant
34 * CSS redistribution rights.
35 *
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions
38 * are met:
39 * 1. Redistributions of source code must retain the above copyright
40 * notice, this list of conditions and the following disclaimer.
41 * 2. Redistributions in binary form must reproduce the above copyright
42 * notice, this list of conditions and the following disclaimer in the
43 * documentation and/or other materials provided with the distribution.
44 * 3. All advertising materials mentioning features or use of this software
45 * must display the following acknowledgement:
46 * This product includes software developed by the University of
47 * California, Berkeley and its contributors.
48 * 4. Neither the name of the University nor the names of its contributors
49 * may be used to endorse or promote products derived from this software
50 * without specific prior written permission.
51 *
52 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
53 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
54 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
55 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
56 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
57 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
58 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
59 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
60 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
61 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
62 * SUCH DAMAGE.
63 *
64 * @(#)bpf.c 8.1 (Berkeley) 6/4/93
65 *
66 * Utah $Hdr: bpf.c 3.1 92/07/06$
67 * Author: Jeff Forys, University of Utah CSS
68 */
69
70 #ifndef lint
71 static char sccsid[] = "@(#)bpf.c 8.1 (Berkeley) 6/4/93";
72 #endif /* not lint */
73
74 #include <sys/param.h>
75 #include <sys/ioctl.h>
76 #include <sys/socket.h>
77
78 #include <net/if.h>
79 #include <net/bpf.h>
80
81 #include <ctype.h>
82 #include <errno.h>
83 #include <fcntl.h>
84 #include <stdio.h>
85 #include <stdlib.h>
86 #include <string.h>
87 #include <syslog.h>
88 #include <unistd.h>
89 #include "defs.h"
90 #include "pathnames.h"
91
92 static int BpfFd = -1;
93 static unsigned BpfLen = 0;
94 static u_char *BpfPkt = NULL;
95
96 /*
97 ** BpfOpen -- Open and initialize a BPF device.
98 **
99 ** Parameters:
100 ** None.
101 **
102 ** Returns:
103 ** File descriptor of opened BPF device (for select() etc).
104 **
105 ** Side Effects:
106 ** If an error is encountered, the program terminates here.
107 */
108 int
109 BpfOpen()
110 {
111 struct ifreq ifr;
112 char bpfdev[32];
113 int n = 0;
114
115 /*
116 * Open the first available BPF device.
117 */
118 do {
119 (void) sprintf(bpfdev, _PATH_BPF, n++);
120 BpfFd = open(bpfdev, O_RDWR);
121 } while (BpfFd < 0 && (errno == EBUSY || errno == EPERM));
122
123 if (BpfFd < 0) {
124 syslog(LOG_ERR, "bpf: no available devices: %m");
125 Exit(0);
126 }
127
128 /*
129 * Set interface name for bpf device, get data link layer
130 * type and make sure it's type Ethernet.
131 */
132 (void) strncpy(ifr.ifr_name, IntfName, sizeof(ifr.ifr_name));
133 if (ioctl(BpfFd, BIOCSETIF, (caddr_t)&ifr) < 0) {
134 syslog(LOG_ERR, "bpf: ioctl(BIOCSETIF,%s): %m", IntfName);
135 Exit(0);
136 }
137
138 /*
139 * Make sure we are dealing with an Ethernet device.
140 */
141 if (ioctl(BpfFd, BIOCGDLT, (caddr_t)&n) < 0) {
142 syslog(LOG_ERR, "bpf: ioctl(BIOCGDLT): %m");
143 Exit(0);
144 }
145 if (n != DLT_EN10MB) {
146 syslog(LOG_ERR,"bpf: %s: data-link type %d unsupported",
147 IntfName, n);
148 Exit(0);
149 }
150
151 /*
152 * On read(), return packets immediately (do not buffer them).
153 */
154 n = 1;
155 if (ioctl(BpfFd, BIOCIMMEDIATE, (caddr_t)&n) < 0) {
156 syslog(LOG_ERR, "bpf: ioctl(BIOCIMMEDIATE): %m");
157 Exit(0);
158 }
159
160 /*
161 * Try to enable the chip/driver's multicast address filter to
162 * grab our RMP address. If this fails, try promiscuous mode.
163 * If this fails, there's no way we are going to get any RMP
164 * packets so just exit here.
165 */
166 #ifdef MSG_EOR
167 ifr.ifr_addr.sa_len = RMP_ADDRLEN + 2;
168 #endif
169 ifr.ifr_addr.sa_family = AF_UNSPEC;
170 bcopy(&RmpMcastAddr[0], (char *)&ifr.ifr_addr.sa_data[0], RMP_ADDRLEN);
171 if (ioctl(BpfFd, SIOCADDMULTI, (caddr_t)&ifr) < 0) {
172 syslog(LOG_WARNING,
173 "bpf: can't add mcast addr (%m), setting promiscuous mode");
174
175 if (ioctl(BpfFd, BIOCPROMISC, (caddr_t)0) < 0) {
176 syslog(LOG_ERR, "bpf: can't set promiscuous mode: %m");
177 Exit(0);
178 }
179 }
180
181 /*
182 * Ask BPF how much buffer space it requires and allocate one.
183 */
184 if (ioctl(BpfFd, BIOCGBLEN, (caddr_t)&BpfLen) < 0) {
185 syslog(LOG_ERR, "bpf: ioctl(BIOCGBLEN): %m");
186 Exit(0);
187 }
188 if (BpfPkt == NULL)
189 BpfPkt = (u_char *)malloc(BpfLen);
190
191 if (BpfPkt == NULL) {
192 syslog(LOG_ERR, "bpf: out of memory (%u bytes for bpfpkt)",
193 BpfLen);
194 Exit(0);
195 }
196
197 /*
198 * Write a little program to snarf RMP Boot packets and stuff
199 * it down BPF's throat (i.e. set up the packet filter).
200 */
201 {
202 #define RMP ((struct rmp_packet *)0)
203 static struct bpf_insn bpf_insn[] = {
204 { BPF_LD|BPF_B|BPF_ABS, 0, 0, (long)&RMP->hp_llc.dsap },
205 { BPF_JMP|BPF_JEQ|BPF_K, 0, 5, IEEE_DSAP_HP },
206 { BPF_LD|BPF_H|BPF_ABS, 0, 0, (long)&RMP->hp_llc.cntrl },
207 { BPF_JMP|BPF_JEQ|BPF_K, 0, 3, IEEE_CNTL_HP },
208 { BPF_LD|BPF_H|BPF_ABS, 0, 0, (long)&RMP->hp_llc.dxsap },
209 { BPF_JMP|BPF_JEQ|BPF_K, 0, 1, HPEXT_DXSAP },
210 { BPF_RET|BPF_K, 0, 0, RMP_MAX_PACKET },
211 { BPF_RET|BPF_K, 0, 0, 0x0 }
212 };
213 #undef RMP
214 static struct bpf_program bpf_pgm = {
215 sizeof(bpf_insn)/sizeof(bpf_insn[0]), bpf_insn
216 };
217
218 if (ioctl(BpfFd, BIOCSETF, (caddr_t)&bpf_pgm) < 0) {
219 syslog(LOG_ERR, "bpf: ioctl(BIOCSETF): %m");
220 Exit(0);
221 }
222 }
223
224 return(BpfFd);
225 }
226
227 /*
228 ** BPF GetIntfName -- Return the name of a network interface attached to
229 ** the system, or 0 if none can be found. The interface
230 ** must be configured up; the lowest unit number is
231 ** preferred; loopback is ignored.
232 **
233 ** Parameters:
234 ** errmsg - if no network interface found, *errmsg explains why.
235 **
236 ** Returns:
237 ** A (static) pointer to interface name, or NULL on error.
238 **
239 ** Side Effects:
240 ** None.
241 */
242 char *
243 BpfGetIntfName(errmsg)
244 char **errmsg;
245 {
246 struct ifreq ibuf[8], *ifrp, *ifend, *mp;
247 struct ifconf ifc;
248 int fd;
249 int minunit, n;
250 char *cp;
251 static char device[sizeof(ifrp->ifr_name)];
252 static char errbuf[128] = "No Error!";
253
254 if (errmsg != NULL)
255 *errmsg = errbuf;
256
257 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
258 (void) strcpy(errbuf, "bpf: socket: %m");
259 return(NULL);
260 }
261 ifc.ifc_len = sizeof ibuf;
262 ifc.ifc_buf = (caddr_t)ibuf;
263
264 #ifdef OSIOCGIFCONF
265 if (ioctl(fd, OSIOCGIFCONF, (char *)&ifc) < 0 ||
266 ifc.ifc_len < sizeof(struct ifreq)) {
267 (void) strcpy(errbuf, "bpf: ioctl(OSIOCGIFCONF): %m");
268 return(NULL);
269 }
270 #else
271 if (ioctl(fd, SIOCGIFCONF, (char *)&ifc) < 0 ||
272 ifc.ifc_len < sizeof(struct ifreq)) {
273 (void) strcpy(errbuf, "bpf: ioctl(SIOCGIFCONF): %m");
274 return(NULL);
275 }
276 #endif
277 ifrp = ibuf;
278 ifend = (struct ifreq *)((char *)ibuf + ifc.ifc_len);
279
280 mp = 0;
281 minunit = 666;
282 for (; ifrp < ifend; ++ifrp) {
283 if (ioctl(fd, SIOCGIFFLAGS, (char *)ifrp) < 0) {
284 (void) strcpy(errbuf, "bpf: ioctl(SIOCGIFFLAGS): %m");
285 return(NULL);
286 }
287
288 /*
289 * If interface is down or this is the loopback interface,
290 * ignore it.
291 */
292 if ((ifrp->ifr_flags & IFF_UP) == 0 ||
293 #ifdef IFF_LOOPBACK
294 (ifrp->ifr_flags & IFF_LOOPBACK))
295 #else
296 (strcmp(ifrp->ifr_name, "lo0") == 0))
297 #endif
298 continue;
299
300 for (cp = ifrp->ifr_name; !isdigit(*cp); ++cp)
301 ;
302 n = atoi(cp);
303 if (n < minunit) {
304 minunit = n;
305 mp = ifrp;
306 }
307 }
308
309 (void) close(fd);
310 if (mp == 0) {
311 (void) strcpy(errbuf, "bpf: no interfaces found");
312 return(NULL);
313 }
314
315 (void) strcpy(device, mp->ifr_name);
316 return(device);
317 }
318
319 /*
320 ** BpfRead -- Read packets from a BPF device and fill in `rconn'.
321 **
322 ** Parameters:
323 ** rconn - filled in with next packet.
324 ** doread - is True if we can issue a read() syscall.
325 **
326 ** Returns:
327 ** True if `rconn' contains a new packet, False otherwise.
328 **
329 ** Side Effects:
330 ** None.
331 */
332 int
333 BpfRead(rconn, doread)
334 RMPCONN *rconn;
335 int doread;
336 {
337 register int datlen, caplen, hdrlen;
338 static u_char *bp = NULL, *ep = NULL;
339 int cc;
340
341 /*
342 * The read() may block, or it may return one or more packets.
343 * We let the caller decide whether or not we can issue a read().
344 */
345 if (doread) {
346 if ((cc = read(BpfFd, (char *)BpfPkt, (int)BpfLen)) < 0) {
347 syslog(LOG_ERR, "bpf: read: %m");
348 return(0);
349 } else {
350 bp = BpfPkt;
351 ep = BpfPkt + cc;
352 }
353 }
354
355 #define bhp ((struct bpf_hdr *)bp)
356 /*
357 * If there is a new packet in the buffer, stuff it into `rconn'
358 * and return a success indication.
359 */
360 if (bp < ep) {
361 datlen = bhp->bh_datalen;
362 caplen = bhp->bh_caplen;
363 hdrlen = bhp->bh_hdrlen;
364
365 if (caplen != datlen)
366 syslog(LOG_ERR,
367 "bpf: short packet dropped (%d of %d bytes)",
368 caplen, datlen);
369 else if (caplen > sizeof(struct rmp_packet))
370 syslog(LOG_ERR, "bpf: large packet dropped (%d bytes)",
371 caplen);
372 else {
373 rconn->rmplen = caplen;
374 bcopy((char *)&bhp->bh_tstamp, (char *)&rconn->tstamp,
375 sizeof(struct timeval));
376 bcopy((char *)bp + hdrlen, (char *)&rconn->rmp, caplen);
377 }
378 bp += BPF_WORDALIGN(caplen + hdrlen);
379 return(1);
380 }
381 #undef bhp
382
383 return(0);
384 }
385
386 /*
387 ** BpfWrite -- Write packet to BPF device.
388 **
389 ** Parameters:
390 ** rconn - packet to send.
391 **
392 ** Returns:
393 ** True if write succeeded, False otherwise.
394 **
395 ** Side Effects:
396 ** None.
397 */
398 int
399 BpfWrite(rconn)
400 RMPCONN *rconn;
401 {
402 if (write(BpfFd, (char *)&rconn->rmp, rconn->rmplen) < 0) {
403 syslog(LOG_ERR, "write: %s: %m", EnetStr(rconn));
404 return(0);
405 }
406
407 return(1);
408 }
409
410 /*
411 ** BpfClose -- Close a BPF device.
412 **
413 ** Parameters:
414 ** None.
415 **
416 ** Returns:
417 ** Nothing.
418 **
419 ** Side Effects:
420 ** None.
421 */
422 void
423 BpfClose()
424 {
425 struct ifreq ifr;
426
427 if (BpfPkt != NULL) {
428 free((char *)BpfPkt);
429 BpfPkt = NULL;
430 }
431
432 if (BpfFd == -1)
433 return;
434
435 #ifdef MSG_EOR
436 ifr.ifr_addr.sa_len = RMP_ADDRLEN + 2;
437 #endif
438 ifr.ifr_addr.sa_family = AF_UNSPEC;
439 bcopy(&RmpMcastAddr[0], (char *)&ifr.ifr_addr.sa_data[0], RMP_ADDRLEN);
440 if (ioctl(BpfFd, SIOCDELMULTI, (caddr_t)&ifr) < 0)
441 (void) ioctl(BpfFd, BIOCPROMISC, (caddr_t)0);
442
443 (void) close(BpfFd);
444 BpfFd = -1;
445 }