+ case ETHERTYPE_ATALK:
+ case ETHERTYPE_AARP:
+ /*
+ * EtherTalk (AppleTalk protocols on Ethernet link
+ * layer) may use 802.2 encapsulation.
+ */
+
+ /*
+ * Check for 802.2 encapsulation (EtherTalk phase 2?);
+ * we check for the 802.2 protocol type in the
+ * "Ethernet type" field.
+ */
+ b0 = gen_cmp(off_linktype, BPF_H, LINUX_SLL_P_802_2);
+
+ /*
+ * 802.2-encapsulated ETHERTYPE_ATALK packets are
+ * SNAP packets with an organization code of
+ * 0x080007 (Apple, for Appletalk) and a protocol
+ * type of ETHERTYPE_ATALK (Appletalk).
+ *
+ * 802.2-encapsulated ETHERTYPE_AARP packets are
+ * SNAP packets with an organization code of
+ * 0x000000 (encapsulated Ethernet) and a protocol
+ * type of ETHERTYPE_AARP (Appletalk ARP).
+ */
+ if (proto == ETHERTYPE_ATALK)
+ b1 = gen_snap(0x080007, ETHERTYPE_ATALK,
+ off_linktype + 2);
+ else /* proto == ETHERTYPE_AARP */
+ b1 = gen_snap(0x000000, ETHERTYPE_AARP,
+ off_linktype + 2);
+ gen_and(b0, b1);
+
+ /*
+ * Check for Ethernet encapsulation (Ethertalk
+ * phase 1?); we just check for the Ethernet
+ * protocol type.
+ */
+ b0 = gen_cmp(off_linktype, BPF_H, (bpf_int32)proto);
+
+ gen_or(b0, b1);
+ return b1;
+
+ default:
+ if (proto <= ETHERMTU) {
+ /*
+ * This is an LLC SAP value, so the frames
+ * that match would be 802.2 frames.
+ * Check for the 802.2 protocol type
+ * in the "Ethernet type" field, and
+ * then check the DSAP.
+ */
+ b0 = gen_cmp(off_linktype, BPF_H,
+ LINUX_SLL_P_802_2);
+ b1 = gen_cmp(off_linktype + 2, BPF_B,
+ (bpf_int32)proto);
+ gen_and(b0, b1);
+ return b1;
+ } else {
+ /*
+ * This is an Ethernet type, so compare
+ * the length/type field with it (if
+ * the frame is an 802.2 frame, the length
+ * field will be <= ETHERMTU, and, as
+ * "proto" is > ETHERMTU, this test
+ * will fail and the frame won't match,
+ * which is what we want).
+ */
+ return gen_cmp(off_linktype, BPF_H,
+ (bpf_int32)proto);
+ }
+ }
+ break;
+
+ case DLT_SLIP:
+ case DLT_SLIP_BSDOS:
+ case DLT_RAW:
+ /*
+ * These types don't provide any type field; packets
+ * are always IP.
+ *
+ * XXX - for IPv4, check for a version number of 4, and,
+ * for IPv6, check for a version number of 6?
+ */
+ switch (proto) {
+
+ case ETHERTYPE_IP:
+#ifdef INET6
+ case ETHERTYPE_IPV6:
+#endif
+ return gen_true(); /* always true */
+
+ default:
+ return gen_false(); /* always false */
+ }
+ break;
+
+ case DLT_PPP:
+ case DLT_PPP_SERIAL:
+ case DLT_PPP_ETHER:
+ /*
+ * We use Ethernet protocol types inside libpcap;
+ * map them to the corresponding PPP protocol types.
+ */
+ switch (proto) {
+
+ case ETHERTYPE_IP:
+ proto = PPP_IP; /* XXX was 0x21 */
+ break;
+
+#ifdef INET6
+ case ETHERTYPE_IPV6:
+ proto = PPP_IPV6;
+ break;
+#endif
+
+ case ETHERTYPE_DN:
+ proto = PPP_DECNET;
+ break;
+
+ case ETHERTYPE_ATALK:
+ proto = PPP_APPLE;
+ break;
+
+ case ETHERTYPE_NS:
+ proto = PPP_NS;
+ break;
+
+ case LLCSAP_ISONS:
+ proto = PPP_OSI;
+ break;
+
+ case LLCSAP_8021D:
+ /*
+ * I'm assuming the "Bridging PDU"s that go
+ * over PPP are Spanning Tree Protocol
+ * Bridging PDUs.
+ */
+ proto = PPP_BRPDU;
+ break;
+
+ case LLCSAP_IPX:
+ proto = PPP_IPX;
+ break;
+ }
+ break;
+
+ case DLT_PPP_BSDOS:
+ /*
+ * We use Ethernet protocol types inside libpcap;
+ * map them to the corresponding PPP protocol types.
+ */
+ switch (proto) {
+
+ case ETHERTYPE_IP:
+ b0 = gen_cmp(off_linktype, BPF_H, PPP_IP);
+ b1 = gen_cmp(off_linktype, BPF_H, PPP_VJC);
+ gen_or(b0, b1);
+ b0 = gen_cmp(off_linktype, BPF_H, PPP_VJNC);
+ gen_or(b1, b0);
+ return b0;
+
+#ifdef INET6
+ case ETHERTYPE_IPV6:
+ proto = PPP_IPV6;
+ /* more to go? */
+ break;
+#endif
+
+ case ETHERTYPE_DN:
+ proto = PPP_DECNET;
+ break;
+
+ case ETHERTYPE_ATALK:
+ proto = PPP_APPLE;
+ break;
+
+ case ETHERTYPE_NS:
+ proto = PPP_NS;
+ break;
+
+ case LLCSAP_ISONS:
+ proto = PPP_OSI;
+ break;
+
+ case LLCSAP_8021D:
+ /*
+ * I'm assuming the "Bridging PDU"s that go
+ * over PPP are Spanning Tree Protocol
+ * Bridging PDUs.
+ */
+ proto = PPP_BRPDU;
+ break;
+
+ case LLCSAP_IPX:
+ proto = PPP_IPX;
+ break;
+ }
+ break;
+
+ case DLT_NULL:
+ case DLT_LOOP:
+ /*
+ * For DLT_NULL, the link-layer header is a 32-bit
+ * word containing an AF_ value in *host* byte order.
+ *
+ * In addition, if we're reading a saved capture file,
+ * the host byte order in the capture may not be the
+ * same as the host byte order on this machine.
+ *
+ * For DLT_LOOP, the link-layer header is a 32-bit
+ * word containing an AF_ value in *network* byte order.
+ *
+ * XXX - AF_ values may, unfortunately, be platform-
+ * dependent; for example, FreeBSD's AF_INET6 is 24
+ * whilst NetBSD's and OpenBSD's is 26.
+ *
+ * This means that, when reading a capture file, just
+ * checking for our AF_INET6 value won't work if the
+ * capture file came from another OS.
+ */
+ switch (proto) {
+
+ case ETHERTYPE_IP:
+ proto = AF_INET;
+ break;
+
+#ifdef INET6
+ case ETHERTYPE_IPV6:
+ proto = AF_INET6;
+ break;
+#endif
+
+ default:
+ /*
+ * Not a type on which we support filtering.
+ * XXX - support those that have AF_ values
+ * #defined on this platform, at least?
+ */
+ return gen_false();
+ }
+
+ if (linktype == DLT_NULL) {
+ /*
+ * The AF_ value is in host byte order, but
+ * the BPF interpreter will convert it to
+ * network byte order.
+ *
+ * If this is a save file, and it's from a
+ * machine with the opposite byte order to
+ * ours, we byte-swap the AF_ value.
+ *
+ * Then we run it through "htonl()", and
+ * generate code to compare against the result.
+ */
+ if (bpf_pcap->sf.rfile != NULL &&
+ bpf_pcap->sf.swapped)
+ proto = SWAPLONG(proto);
+ proto = htonl(proto);
+ }
+ return (gen_cmp(0, BPF_W, (bpf_int32)proto));
+
+ case DLT_ARCNET:
+ /*
+ * XXX should we check for first fragment if the protocol
+ * uses PHDS?
+ */
+ switch(proto) {
+ default:
+ return gen_false();
+#ifdef INET6
+ case ETHERTYPE_IPV6:
+ return(gen_cmp(2, BPF_B,
+ (bpf_int32)htonl(ARCTYPE_INET6)));
+#endif /* INET6 */
+ case ETHERTYPE_IP:
+ b0 = gen_cmp(2, BPF_B, (bpf_int32)htonl(ARCTYPE_IP));
+ b1 = gen_cmp(2, BPF_B,
+ (bpf_int32)htonl(ARCTYPE_IP_OLD));
+ gen_or(b0, b1);
+ return(b1);
+ case ETHERTYPE_ARP:
+ b0 = gen_cmp(2, BPF_B, (bpf_int32)htonl(ARCTYPE_ARP));
+ b1 = gen_cmp(2, BPF_B,
+ (bpf_int32)htonl(ARCTYPE_ARP_OLD));
+ gen_or(b0, b1);
+ return(b1);
+ case ETHERTYPE_REVARP:
+ return(gen_cmp(2, BPF_B,
+ (bpf_int32)htonl(ARCTYPE_REVARP)));
+ case ETHERTYPE_ATALK:
+ return(gen_cmp(2, BPF_B,
+ (bpf_int32)htonl(ARCTYPE_ATALK)));
+ }
+ break;
+
+ case DLT_LTALK:
+ switch (proto) {
+ case ETHERTYPE_ATALK:
+ return gen_true();
+ default:
+ return gen_false();
+ }
+ break;
+ }
+
+ /*
+ * All the types that have no encapsulation should either be
+ * handled as DLT_SLIP, DLT_SLIP_BSDOS, and DLT_RAW are, if
+ * all packets are IP packets, or should be handled in some
+ * special case, if none of them are (if some are and some
+ * aren't, the lack of encapsulation is a problem, as we'd
+ * have to find some other way of determining the packet type).
+ *
+ * Therefore, if "off_linktype" is -1, there's an error.
+ */
+ if (off_linktype == -1)
+ abort();
+
+ /*
+ * Any type not handled above should always have an Ethernet
+ * type at an offset of "off_linktype". (PPP is partially
+ * handled above - the protocol type is mapped from the
+ * Ethernet and LLC types we use internally to the corresponding
+ * PPP type - but the PPP type is always specified by a value
+ * at "off_linktype", so we don't have to do the code generation
+ * above.)
+ */
+ return gen_cmp(off_linktype, BPF_H, (bpf_int32)proto);
+}
+
+/*
+ * Check for an LLC SNAP packet with a given organization code and
+ * protocol type; we check the entire contents of the 802.2 LLC and
+ * snap headers, checking for DSAP and SSAP of SNAP and a control
+ * field of 0x03 in the LLC header, and for the specified organization
+ * code and protocol type in the SNAP header.
+ */
+static struct block *
+gen_snap(orgcode, ptype, offset)
+ bpf_u_int32 orgcode;
+ bpf_u_int32 ptype;
+ u_int offset;
+{
+ u_char snapblock[8];
+
+ snapblock[0] = LLCSAP_SNAP; /* DSAP = SNAP */
+ snapblock[1] = LLCSAP_SNAP; /* SSAP = SNAP */
+ snapblock[2] = 0x03; /* control = UI */
+ snapblock[3] = (orgcode >> 16); /* upper 8 bits of organization code */
+ snapblock[4] = (orgcode >> 8); /* middle 8 bits of organization code */
+ snapblock[5] = (orgcode >> 0); /* lower 8 bits of organization code */
+ snapblock[6] = (ptype >> 8); /* upper 8 bits of protocol type */
+ snapblock[7] = (ptype >> 0); /* lower 8 bits of protocol type */
+ return gen_bcmp(offset, 8, snapblock);
+}
+
+static struct block *
+gen_hostop(addr, mask, dir, proto, src_off, dst_off)
+ bpf_u_int32 addr;
+ bpf_u_int32 mask;
+ int dir, proto;
+ u_int src_off, dst_off;
+{
+ struct block *b0, *b1;
+ u_int offset;
+
+ switch (dir) {
+
+ case Q_SRC:
+ offset = src_off;
+ break;
+
+ case Q_DST:
+ offset = dst_off;
+ break;
+
+ case Q_AND:
+ b0 = gen_hostop(addr, mask, Q_SRC, proto, src_off, dst_off);
+ b1 = gen_hostop(addr, mask, Q_DST, proto, src_off, dst_off);
+ gen_and(b0, b1);
+ return b1;
+
+ case Q_OR:
+ case Q_DEFAULT:
+ b0 = gen_hostop(addr, mask, Q_SRC, proto, src_off, dst_off);
+ b1 = gen_hostop(addr, mask, Q_DST, proto, src_off, dst_off);
+ gen_or(b0, b1);
+ return b1;
+
+ default:
+ abort();
+ }
+ b0 = gen_linktype(proto);
+ b1 = gen_mcmp(offset, BPF_W, (bpf_int32)addr, mask);
+ gen_and(b0, b1);
+ return b1;
+}
+
+#ifdef INET6
+static struct block *
+gen_hostop6(addr, mask, dir, proto, src_off, dst_off)
+ struct in6_addr *addr;
+ struct in6_addr *mask;
+ int dir, proto;
+ u_int src_off, dst_off;
+{
+ struct block *b0, *b1;
+ u_int offset;
+ u_int32_t *a, *m;
+
+ switch (dir) {
+
+ case Q_SRC:
+ offset = src_off;
+ break;
+
+ case Q_DST:
+ offset = dst_off;
+ break;
+
+ case Q_AND:
+ b0 = gen_hostop6(addr, mask, Q_SRC, proto, src_off, dst_off);
+ b1 = gen_hostop6(addr, mask, Q_DST, proto, src_off, dst_off);
+ gen_and(b0, b1);
+ return b1;
+
+ case Q_OR:
+ case Q_DEFAULT:
+ b0 = gen_hostop6(addr, mask, Q_SRC, proto, src_off, dst_off);
+ b1 = gen_hostop6(addr, mask, Q_DST, proto, src_off, dst_off);
+ gen_or(b0, b1);
+ return b1;
+
+ default:
+ abort();
+ }
+ /* this order is important */
+ a = (u_int32_t *)addr;
+ m = (u_int32_t *)mask;
+ b1 = gen_mcmp(offset + 12, BPF_W, ntohl(a[3]), ntohl(m[3]));
+ b0 = gen_mcmp(offset + 8, BPF_W, ntohl(a[2]), ntohl(m[2]));
+ gen_and(b0, b1);
+ b0 = gen_mcmp(offset + 4, BPF_W, ntohl(a[1]), ntohl(m[1]));
+ gen_and(b0, b1);
+ b0 = gen_mcmp(offset + 0, BPF_W, ntohl(a[0]), ntohl(m[0]));
+ gen_and(b0, b1);
+ b0 = gen_linktype(proto);
+ gen_and(b0, b1);
+ return b1;
+}
+#endif /*INET6*/
+
+static struct block *
+gen_ehostop(eaddr, dir)
+ register const u_char *eaddr;
+ register int dir;
+{
+ register struct block *b0, *b1;
+
+ switch (dir) {
+ case Q_SRC:
+ return gen_bcmp(6, 6, eaddr);
+
+ case Q_DST:
+ return gen_bcmp(0, 6, eaddr);
+
+ case Q_AND:
+ b0 = gen_ehostop(eaddr, Q_SRC);
+ b1 = gen_ehostop(eaddr, Q_DST);
+ gen_and(b0, b1);