📄 bpf.c
字号:
/* $Header: /usr/cvsroot/target/src/wrn/wm/demo/lib/bpf.c,v 1.3 2003/01/15 14:04:30 josh Exp $ *//* * Copyright (C) 1999-2005 Wind River Systems, Inc. * All rights reserved. Provided under license only. * Distribution or other use of this software is only * permitted pursuant to the terms of a license agreement * from Wind River Systems (and is otherwise prohibited). * Refer to that license agreement for terms of use. *//**************************************************************************** * Copyright 1993-1997 Epilogue Technology Corporation. * Copyright 1998 Integrated Systems, Inc. * All rights reserved. ****************************************************************************//* * $Log: bpf.c,v $ * Revision 1.3 2003/01/15 14:04:30 josh * directory structure shifting * * Revision 1.2 2001/11/08 15:56:20 tneale * Updated for newest file layout * * Revision 1.1.1.1 2001/11/05 17:48:41 tneale * Tornado shuffle * * Revision 2.14 2001/01/19 22:23:38 paul * Update copyright. * * Revision 2.13 2000/10/16 19:21:49 paul * Restore sockets and mempool code. * * Revision 2.12 2000/03/17 00:12:36 meister * Update copyright message * * Revision 2.11 2000/03/13 21:22:01 paul * Removed some code that we are no longer working on. * * Revision 2.10 1999/02/18 04:41:32 wes * Sockets merge: Everything Else * - memory pools * - thread support * - port-specific headers * * Revision 2.9.12.1 1998/09/23 19:17:15 wes * Merge socket-branch-1 changes to socket-branch-2 * * Revision 2.9.10.1 1998/08/19 13:26:22 wes * Merge sockets-pthreads work to shared branch * * Revision 2.9.4.1 1998/08/05 20:48:47 wes * XXX: Deal with mit-pthreads header file dane brammage * * Revision 2.9 1998/04/09 22:03:08 wes * Rip out ntohl/ntohs stuff since anyone still running NetBSD 0.8 gets what they deserve... * * Revision 2.8 1998/02/25 04:57:20 sra * Update copyrights. * * Revision 2.7 1998/02/17 18:28:53 sra * Add filter support for IPv4 multicast. * * Revision 2.6 1997/06/03 05:12:30 sra * Tighter BPF filter (souvenir of N+I Vegas '97). * * Revision 2.5 1997/04/25 01:02:25 sra * Fix code to set explicit MAC addresses for BPF, allow non-promiscuous mode. * * Revision 2.4 1997/03/20 06:52:51 sra * DFARS-safe copyright text. Zap! * * Revision 2.3 1997/02/25 10:58:16 sra * Update copyright notice, dust under the bed. * * Revision 2.2 1996/03/22 10:05:39 sra * Update copyrights prior to Attache 3.2 release. * * Revision 2.1 1995/06/22 05:29:06 sra * Preliminary changes for multicast and OSPF. * * Revision 2.0 1995/05/10 22:38:15 sra * Attache release 3.0. * * Revision 1.4 1995/01/06 00:52:48 sra * Update copyright notice for 2.1 release. * * Revision 1.3 1994/09/02 21:15:48 sra * Add still more parentheses to the for() loop from hell in bpf_find(). * * Revision 1.2 1993/07/29 04:30:26 sra * Don't use the inline versions of the byteswap routines, GCC gets * confused. * * Revision 1.1 1993/07/05 21:53:30 sra * Initial revision * *//* [clearcase]modification history-------------------01a,19apr05,job update copyright notices*//* * BPF interface to ethernet for attache testing under 386BSD/NetBSD/FreeBSD. * * All access to BPF should be through this module, the only thing we * expect our caller to do with our file descriptor is use it in * select() calls. There are enough name conflicts between the unix * networking code and the Attache networking code that it's probably * hopeless to have the two mingled in the same file. * * References: BPF sample RARP server * tcpdump { bpf_image.c, bpf_dump.c, pcap-bpf.c } * bpf(4) manual page * netintro(4) manual page * routed.c */#include <stdio.h>#include <errno.h>#include <string.h>#include <unistd.h>#include <stdlib.h>#include <sys/param.h>#include <sys/types.h>#include <sys/time.h>#include <sys/timeb.h>#include <sys/socket.h>#include <sys/file.h>#include <sys/ioctl.h>#include <net/bpf.h>#include <net/if.h>#include <net/if_dl.h>#include <net/if_types.h>#include <netinet/in.h>#include <wrn/wm/common/install.h>/* * Stuff dealing with the BPF filter itself. */#ifndef INSTALL_SNARK_BSD_BPF_LOOSE_FILTER#define INSTALL_SNARK_BSD_BPF_LOOSE_FILTER 0#endif#ifndef INSTALL_SNARK_BSD_BPF_NO_V4_MULTICAST#define INSTALL_SNARK_BSD_BPF_NO_V4_MULTICAST 0#endif#if INSTALL_SNARK_BSD_BPF_LOOSE_FILTER/* * Filter expression (see tcpdump(1) man page for translation): * '-s 1500 ether multicast or ether dst e1:e2:e3:e4:e5:e6' */static struct bpf_insn instructions[] = { { 0x30, 0, 0, 0x00000000 }, /* (000) ldb [0] */ { 0x45, 4, 0, 0x00000001 }, /* (001) jset #0x1 jt 6 jf 2 */ { 0x20, 0, 0, 0x00000002 }, /* (002) ld [2] */ { 0x15, 0, 3, 0xe3e4e5e6 }, /* (003) jeq #0xe3e4e5e6 jt 4 jf 7 */ { 0x28, 0, 0, 0x00000000 }, /* (004) ldh [0] */ { 0x15, 0, 1, 0x0000e1e2 }, /* (005) jeq #0xe1e2 jt 6 jf 7 */ { 0x6, 0, 0, 0x000005dc }, /* (006) ret #1500 */ { 0x6, 0, 0, 0x00000000 }, /* (007) ret #0 */};#else /* INSTALL_SNARK_BSD_BPF_LOOSE_FILTER */#if INSTALL_SNARK_BSD_BPF_NO_V4_MULTICAST/* * Filter expression (see tcpdump(1) man page for translation): * '-s 1514 ether[0:2] = 0x3333 or ether broadcast or ether dst e1:e2:e3:d4:e5:e6' */static struct bpf_insn instructions[] = { { 0x28, 0, 0, 0x00000000 }, /* (000) ldh [0] */ { 0x15, 7, 0, 0x00003333 }, /* (001) jeq #0x3333 jt 9 jf 2 */ { 0x20, 0, 0, 0x00000002 }, /* (002) ld [2] */ { 0x15, 0, 2, 0xffffffff }, /* (003) jeq #0xffffffff jt 4 jf 6 */ { 0x28, 0, 0, 0x00000000 }, /* (004) ldh [0] */ { 0x15, 3, 4, 0x0000ffff }, /* (005) jeq #0xffff jt 9 jf 10 */ { 0x15, 0, 3, 0xe3d4e5e6 }, /* (006) jeq #0xe3d4e5e6 jt 7 jf 10 */ { 0x28, 0, 0, 0x00000000 }, /* (007) ldh [0] */ { 0x15, 0, 1, 0x0000e1e2 }, /* (008) jeq #0xe1e2 jt 9 jf 10 */ { 0x6, 0, 0, 0x000005ea }, /* (009) ret #1514 */ { 0x6, 0, 0, 0x00000000 }, /* (010) ret #0 */};#else /* INSTALL_SNARK_BSD_BPF_NO_V4_MULTICAST *//* * Filter expression (see tcpdump(1) man page for translation): * '-s 1514 ether[0:2] = 0x3333 or ( ether[0:2] = 0x0100 and ether[2:1] = 0x5e ) or ether broadcast or ether dst e1:e2:e3:d4:e5:e6' */static struct bpf_insn instructions[] = { { 0x28, 0, 0, 0x00000000 }, /* (000) ldh [0] */ { 0x15, 10, 0, 0x00003333 }, /* (001) jeq #0x3333 jt 12 jf 2 */ { 0x15, 0, 2, 0x00000100 }, /* (002) jeq #0x100 jt 3 jf 5 */ { 0x30, 0, 0, 0x00000002 }, /* (003) ldb [2] */ { 0x15, 7, 0, 0x0000005e }, /* (004) jeq #0x5e jt 12 jf 5 */ { 0x20, 0, 0, 0x00000002 }, /* (005) ld [2] */ { 0x15, 0, 2, 0xffffffff }, /* (006) jeq #0xffffffff jt 7 jf 9 */ { 0x28, 0, 0, 0x00000000 }, /* (007) ldh [0] */ { 0x15, 3, 4, 0x0000ffff }, /* (008) jeq #0xffff jt 12 jf 13 */ { 0x15, 0, 3, 0xe3d4e5e6 }, /* (009) jeq #0xe3d4e5e6 jt 10 jf 13 */ { 0x28, 0, 0, 0x00000000 }, /* (010) ldh [0] */ { 0x15, 0, 1, 0x0000e1e2 }, /* (011) jeq #0xe1e2 jt 12 jf 13 */ { 0x6, 0, 0, 0x000005ea }, /* (012) ret #1514 */ { 0x6, 0, 0, 0x00000000 }, /* (013) ret #0 */};#endif /* INSTALL_SNARK_BSD_BPF_NO_V4_MULTICAST */#endif /* INSTALL_SNARK_BSD_BPF_LOOSE_FILTER */struct bpf_program filter = { sizeof(instructions) / sizeof(*instructions), instructions};/* * Macros to set filter componants at runtime. These macros should * be the only code that knows anything about the guts of the filter. * * SET_FILTER_MAC sets the filter's MAC addr (in case the board is * in promiscuous mode) to the value of the six-byte string given * as an argument. Presumably this is from the sockaddr sa_data field * or an explict argument given to bpf_open(). * * SET_FILTER_MTU sets the filter MTU for inbound packets; this is really * the truncation length for the kernel, but since it should match the * buffer size you're using it's effectively the same thing. */#if INSTALL_SNARK_BSD_BPF_LOOSE_FILTER#define SET_FILTER_MAC(_x_) \ do { \ instructions[5].k = ntohs(*(u_short *) ((_x_)+0)); \ instructions[3].k = ntohl(*(u_long *) ((_x_)+2)); \ } while (0)#define SET_FILTER_MTU(_x_) \ do { \ instructions[6].k = (_x_); \ } while (0)#else /* INSTALL_SNARK_BSD_BPF_LOOSE_FILTER */#if INSTALL_SNARK_BSD_BPF_NO_V4_MULTICAST#define SET_FILTER_MAC(_x_) \ do { \ instructions[8].k = ntohs(*(u_short *) ((_x_)+0)); \ instructions[6].k = ntohl(*(u_long *) ((_x_)+2)); \ } while (0)#define SET_FILTER_MTU(_x_) \ do { \ instructions[9].k = (_x_); \ } while (0)#else /* INSTALL_SNARK_BSD_BPF_NO_V4_MULTICAST */#define SET_FILTER_MAC(_x_) \ do { \ instructions[11].k = ntohs(*(u_short *) ((_x_)+0)); \ instructions[ 9].k = ntohl(*(u_long *) ((_x_)+2)); \ } while (0)#define SET_FILTER_MTU(_x_) \ do { \ instructions[12].k = (_x_); \ } while (0)#endif /* INSTALL_SNARK_BSD_BPF_NO_V4_MULTICAST */#endif /* INSTALL_SNARK_BSD_BPF_LOOSE_FILTER *//* * Macro for calculating the size of buffer to tell BPF to use, based * on the MTU of the interface. This would be the BPF header size * plus the MTU, except that BPF does some rounding for alignment. The * intent is that the size of buffer we use be just big enough that * BPF will never truncate a packet that we know how to handle. */#define ROUNDED_BPF_MTU(_x_) \ (BPF_WORDALIGN((_x_)) + BPF_WORDALIGN(sizeof(struct bpf_hdr)))/* * Open a BPF file and attach it to the interface named 'device'. * Returns BPF file descriptor, or -1 if an error occurs. * * This is cobbled together from code in rarpd and tcpdump. */int bpf_open(char *ifname, unsigned mtu, unsigned char *mac, int promiscuous){ struct bpf_version bv; struct ifreq ifr; int fd, i; u_int u; /* * Look for a BPF device that's not in use. */ i = 0; do { char bpfname[sizeof "/dev/bpf000"]; (void) sprintf(bpfname, "/dev/bpf%d", i++); fd = open(bpfname, O_RDWR); } while (fd < 0 && errno == EBUSY); if (fd < 0) { perror("couldn't get a BPF device"); return -1; } /* * Check the filter language version number. */ if (ioctl(fd, BIOCVERSION, (char *) &bv) < 0) { fprintf(stderr, "kernel BPF interpreter out of date"); return -1; } else if (bv.bv_major != BPF_MAJOR_VERSION || bv.bv_minor < BPF_MINOR_VERSION) { fprintf(stderr, "requires BPF language %d.%d or higher; kernel is %d.%d", BPF_MAJOR_VERSION, BPF_MINOR_VERSION, bv.bv_major, bv.bv_minor); return -1; } /* * Set immediate mode so packets are processed as they arrive. */ i = 1; if (ioctl(fd, BIOCIMMEDIATE, (char *) &i) < 0) { perror("BIOCIMMEDIATE"); return -1; } /* * Set the read() buffer size. */ u = ROUNDED_BPF_MTU(mtu); if (ioctl(fd, BIOCSBLEN, (char *) &u) < 0) { perror("BIOCSBLEN"); return -1; } /* * Attach the BPF device to the interface. */ (void) strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); if (ioctl(fd, BIOCSETIF, (char *) &ifr) < 0) { perror("BIOCSETIF"); return -1; } /* * Check that the data link layer is an Ethernet; this code won't * work with anything else. */ if (ioctl(fd, BIOCGDLT, (char *) &u) < 0) { perror("BIOCGDLT"); return -1; } if (u != DLT_EN10MB) { fprintf(stderr, "%s is not an ethernet", ifname); return -1; } /* * Put the interface in promiscuous mode so we'll see packets * to our faked MAC address. */ if (promiscuous && ioctl(fd, BIOCPROMISC, 0) < 0) { perror("BIOCPROMISC"); return -1; } /* * If we were given a MAC address, use it to set up a filter. * Otherwise, assume we're happy being in promiscuous mode. */ if (mac) { SET_FILTER_MAC(mac); SET_FILTER_MTU(mtu); if (ioctl(fd, BIOCSETF, (char *) &filter) < 0) { perror("BIOCSETF"); return -1; } } return fd;}/* * Read a BPF buffer and hand its contents off to Attache as packets. * This is based on the readloop() function in tcpdump's BPF code. * * The handler routine supplied by the Attache-side code gets three * arguments: a pointer to the packet data, the length of the packet * data, and the length that the real packet was on the wire. * * There's probably nothing useful that Attache can do with a truncated * packet, but the info is there, so we may as well pass it along. */#define bhp ((struct bpf_hdr *) bp)#if defined(__NetBSD__) && defined(INSTALL_SNARK_THREADS)/* mit_pthreads has broken stdlib.h !!! */#if !defined(_POSIX_C_SOURCE) && !defined(_XOPEN_SOURCE)#if defined(alloca) && (alloca == __builtin_alloca) && (__GNUC__ < 2)void *alloca __P((int)); /* built-in for gcc */ #else void *alloca __P((size_t)); #endif /* __GNUC__ */ #endif#endifint bpf_read (int fd, unsigned mtu, void (*handler)(unsigned char *, unsigned, unsigned, void *), void *cookie){ unsigned char *buf, *bp, *ep; int i; mtu = ROUNDED_BPF_MTU(mtu); if ((buf = (unsigned char *) alloca(mtu)) == 0) { fprintf(stderr, "alloca(%d) failed\n", mtu); return -1; } /* * Try to read a packet, restart if we get screwed by the debugger. * Return on other error or on EOF. */ do { i = read(fd, buf, mtu); } while (i < 0 && errno == EINTR); if (i <= 0) return i; /* * Got a buffer full of data, chop it into packets and hand it off. */ bp = buf; ep = bp + i; for (i = 0; bp < ep; ++i) { handler(bp + bhp->bh_hdrlen, bhp->bh_caplen, bhp->bh_datalen, cookie); bp += BPF_WORDALIGN(bhp->bh_caplen + bhp->bh_hdrlen); } /* * Return the number of packets we got. */ return i;}#undef bhp/* * Write a packet to the BPF file. Per BPF manual page, we can only * write one packet at a time. This shouldn't be a problem. */int bpf_write(int fd, unsigned char *data, unsigned datalen){ return write(fd, data, datalen);}/* * Close a BPF interface. */void bpf_close(int fd){ (void) close(fd);}#if defined(SIOCGIFCONF)/* * Find all ethernet interfaces. Works on NetBSD, your milage may vary. * The "array" returned by SIOCGIFCONF is kinda bizzare.... */void bpf_find(void (*handler)(char *, void *), void *cookie){ char buffer[5000]; struct ifconf ifc; struct ifreq *ifr; int s; if (!handler) return; if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { perror("socket"); return; } ifc.ifc_len = sizeof(buffer); ifc.ifc_buf = buffer; if (ioctl(s, SIOCGIFCONF, (char *) &ifc) < 0) { perror("ioctl"); (void) close(s); return; } for (ifr = ifc.ifc_req; ((char *) ifr) < ifc.ifc_buf + ifc.ifc_len; ifr = ((struct ifreq *) (((char *) ifr) + sizeof(ifr->ifr_name) + ifr->ifr_addr.sa_len))) if (ifr->ifr_addr.sa_family == AF_LINK && ((struct sockaddr_dl *) &ifr->ifr_addr)->sdl_type == IFT_ETHER) handler(ifr->ifr_name, cookie); (void) close(s);}#endif /* defined(SIOCGIFCONF) */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -