X-Git-Url: https://git.tcpdump.org/libpcap/blobdiff_plain/d0e62b4eb24d4c66c88840474f645efa886bc8ff..bc6f4cb8a61b5c60a8027b34b5e680977ab6ac4a:/gencode.c?ds=sidebyside diff --git a/gencode.c b/gencode.c index 4f7c3926..81da02ef 100644 --- a/gencode.c +++ b/gencode.c @@ -21,7 +21,7 @@ */ #ifndef lint static const char rcsid[] _U_ = - "@(#) $Header: /tcpdump/master/libpcap/gencode.c,v 1.221.2.20 2005-05-19 10:05:31 hannes Exp $ (LBL)"; + "@(#) $Header: /tcpdump/master/libpcap/gencode.c,v 1.221.2.41 2006-09-13 07:02:15 guy Exp $ (LBL)"; #endif #ifdef HAVE_CONFIG_H @@ -100,8 +100,8 @@ static const char rcsid[] _U_ = static jmp_buf top_ctx; static pcap_t *bpf_pcap; -/* Hack for updating VLAN, MPLS offsets. */ -static u_int orig_linktype = -1U, orig_nl = -1U; +/* Hack for updating VLAN, MPLS, and PPPoE offsets. */ +static u_int orig_linktype = -1U, orig_nl = -1U, label_stack_depth = -1U; /* XXX */ #ifdef PCAP_FDDIPAD @@ -205,9 +205,10 @@ static struct block *gen_thostop(const u_char *, int); static struct block *gen_wlanhostop(const u_char *, int); static struct block *gen_ipfchostop(const u_char *, int); static struct block *gen_dnhostop(bpf_u_int32, int); -static struct block *gen_host(bpf_u_int32, bpf_u_int32, int, int); +static struct block *gen_mpls_linktype(int); +static struct block *gen_host(bpf_u_int32, bpf_u_int32, int, int, int); #ifdef INET6 -static struct block *gen_host6(struct in6_addr *, struct in6_addr *, int, int); +static struct block *gen_host6(struct in6_addr *, struct in6_addr *, int, int, int); #endif #ifndef INET6 static struct block *gen_gateway(const u_char *, bpf_u_int32 **, int, int); @@ -667,20 +668,26 @@ gen_ncmp(offrel, offset, size, mask, jtype, reverse, v) static int reg_ll_size; /* - * This is the offset of the beginning of the link-layer header. + * This is the offset of the beginning of the link-layer header from + * the beginning of the raw packet data. + * * It's usually 0, except for 802.11 with a fixed-length radio header. + * (For 802.11 with a variable-length radio header, we have to generate + * code to compute that offset; off_ll is 0 in that case.) */ static u_int off_ll; /* * This is the offset of the beginning of the MAC-layer header. - * It's usually 0, except for ATM LANE. + * It's usually 0, except for ATM LANE, where it's the offset, relative + * to the beginning of the raw packet data, of the Ethernet header. */ static u_int off_mac; /* * "off_linktype" is the offset to information in the link-layer header - * giving the packet type. + * giving the packet type. This offset is relative to the beginning + * of the link-layer header (i.e., it doesn't include off_ll). * * For Ethernet, it's the offset of the Ethernet type field. * @@ -717,6 +724,14 @@ static u_int off_vpi; static u_int off_vci; static u_int off_proto; +/* + * These are offsets for the MTP3 fields. + */ +static u_int off_sio; +static u_int off_opc; +static u_int off_dpc; +static u_int off_sls; + /* * This is the offset of the first byte after the ATM pseudo_header, * or -1 if there is no ATM pseudo-header. @@ -725,6 +740,8 @@ static u_int off_payload; /* * These are offsets to the beginning of the network-layer header. + * They are relative to the beginning of the link-layer header (i.e., + * they don't include off_ll). * * If the link layer never uses 802.2 LLC: * @@ -770,6 +787,14 @@ init_linktype(p) off_proto = -1; off_payload = -1; + /* + * And assume we're not doing SS7. + */ + off_sio = -1; + off_opc = -1; + off_dpc = -1; + off_sls = -1; + /* * Also assume it's not 802.11 with a fixed-length radio header. */ @@ -777,6 +802,7 @@ init_linktype(p) orig_linktype = -1; orig_nl = -1; + label_stack_depth = 0; reg_ll_size = -1; @@ -938,9 +964,9 @@ init_linktype(p) * the Prism header is fixed-length. */ off_ll = 144; - off_linktype = 144+24; - off_nl = 144+32; /* Prism+802.11+802.2+SNAP */ - off_nl_nosnap = 144+27; /* Prism+802.11+802.2 */ + off_linktype = 24; + off_nl = 32; /* Prism+802.11+802.2+SNAP */ + off_nl_nosnap = 27; /* Prism+802.11+802.2 */ return; case DLT_IEEE802_11_RADIO_AVS: @@ -956,12 +982,23 @@ init_linktype(p) * more so; this header is also variable-length, * with the length being the 32-bit big-endian * number at an offset of 4 from the beginning - * of the radio header. + * of the radio header. We should handle that the + * same way we handle the length at the beginning + * of the radiotap header. + * + * XXX - in Linux, do any drivers that supply an AVS + * header supply a link-layer type other than + * ARPHRD_IEEE80211_PRISM? If so, we should map that + * to DLT_IEEE802_11_RADIO_AVS; if not, or if there are + * any drivers that supply an AVS header but supply + * an ARPHRD value of ARPHRD_IEEE80211_PRISM, we'll + * have to check the header in the generated code to + * determine whether it's Prism or AVS. */ off_ll = 64; - off_linktype = 64+24; - off_nl = 64+32; /* Radio+802.11+802.2+SNAP */ - off_nl_nosnap = 64+27; /* Radio+802.11+802.2 */ + off_linktype = 24; + off_nl = 32; /* Radio+802.11+802.2+SNAP */ + off_nl_nosnap = 27; /* Radio+802.11+802.2 */ return; case DLT_IEEE802_11_RADIO: @@ -985,6 +1022,13 @@ init_linktype(p) /* * assume routed, non-ISO PDUs * (i.e., LLC = 0xAA-AA-03, OUT = 0x00-00-00) + * + * XXX - what about ISO PDUs, e.g. CLNP, ISIS, ESIS, + * or PPP with the PPP NLPID (e.g., PPPoA)? The + * latter would presumably be treated the way PPPoE + * should be, so you can do "pppoe and udp port 2049" + * or "pppoa and tcp port 80" and have it check for + * PPPo{A,E} and a PPP protocol of IP and.... */ off_linktype = 0; off_nl = 8; /* 802.2+SNAP */ @@ -1056,6 +1100,17 @@ init_linktype(p) off_nl_nosnap = 0; /* no 802.2 LLC */ return; + /* + * the only BPF-interesting FRF.16 frames are non-control frames; + * Frame Relay has a variable length link-layer + * so lets start with offset 4 for now and increments later on (FIXME); + */ + case DLT_MFR: + off_linktype = -1; + off_nl = 4; + off_nl_nosnap = 0; /* XXX - for now -> no 802.2 LLC */ + return; + case DLT_APPLE_IP_OVER_IEEE1394: off_linktype = 16; off_nl = 18; @@ -1093,8 +1148,12 @@ init_linktype(p) off_nl_nosnap = PFLOG_HDRLEN; /* no 802.2 LLC */ return; + case DLT_JUNIPER_MFR: case DLT_JUNIPER_MLFR: case DLT_JUNIPER_MLPPP: + case DLT_JUNIPER_PPP: + case DLT_JUNIPER_CHDLC: + case DLT_JUNIPER_FRELAY: off_linktype = 4; off_nl = 4; off_nl_nosnap = -1; /* no 802.2 LLC */ @@ -1112,43 +1171,54 @@ init_linktype(p) off_nl_nosnap = 18; return; - /* frames captured on a Juniper PPPoE service PIC - * contain raw ethernet frames */ - case DLT_JUNIPER_PPPOE: - off_linktype = 16; - off_nl = 18; /* Ethernet II */ - off_nl_nosnap = 21; /* 802.3+802.2 */ - return; + /* frames captured on a Juniper PPPoE service PIC + * contain raw ethernet frames */ + case DLT_JUNIPER_PPPOE: + case DLT_JUNIPER_ETHER: + off_linktype = 16; + off_nl = 18; /* Ethernet II */ + off_nl_nosnap = 21; /* 802.3+802.2 */ + return; - case DLT_JUNIPER_PPPOE_ATM: - off_linktype = 4; - off_nl = 6; - off_nl_nosnap = -1; /* no 802.2 LLC */ - return; + case DLT_JUNIPER_PPPOE_ATM: + off_linktype = 4; + off_nl = 6; + off_nl_nosnap = -1; /* no 802.2 LLC */ + return; - case DLT_JUNIPER_GGSN: - off_linktype = 6; - off_nl = 12; - off_nl_nosnap = -1; /* no 802.2 LLC */ - return; + case DLT_JUNIPER_GGSN: + off_linktype = 6; + off_nl = 12; + off_nl_nosnap = -1; /* no 802.2 LLC */ + return; - case DLT_JUNIPER_ES: - off_linktype = 6; - off_nl = -1; /* not really a network layer but raw IP adresses */ - off_nl_nosnap = -1; /* no 802.2 LLC */ - return; + case DLT_JUNIPER_ES: + off_linktype = 6; + off_nl = -1; /* not really a network layer but raw IP adresses */ + off_nl_nosnap = -1; /* no 802.2 LLC */ + return; - case DLT_JUNIPER_MONITOR: - off_linktype = 12; - off_nl = 12; /* raw IP/IP6 header */ - off_nl_nosnap = -1; /* no 802.2 LLC */ - return; + case DLT_JUNIPER_MONITOR: + off_linktype = 12; + off_nl = 12; /* raw IP/IP6 header */ + off_nl_nosnap = -1; /* no 802.2 LLC */ + return; - case DLT_JUNIPER_SERVICES: - off_linktype = 12; - off_nl = -1; /* L3 proto location dep. on cookie type */ - off_nl_nosnap = -1; /* no 802.2 LLC */ - return; + case DLT_JUNIPER_SERVICES: + off_linktype = 12; + off_nl = -1; /* L3 proto location dep. on cookie type */ + off_nl_nosnap = -1; /* no 802.2 LLC */ + return; + + case DLT_MTP2: + off_sio = 3; + off_opc = 4; + off_dpc = 4; + off_sls = 7; + off_linktype = -1; + off_nl = -1; + off_nl_nosnap = -1; + return; #ifdef DLT_PFSYNC case DLT_PFSYNC: @@ -1189,6 +1259,9 @@ gen_load_llrel(offset, size) * If "s" is non-null, it has code to arrange that the X register * contains the length of the prefix preceding the link-layer * header. + * + * Otherwise, the length of the prefix preceding the link-layer + * header is "off_ll". */ if (s != NULL) { s2 = new_stmt(BPF_LD|BPF_IND|size); @@ -1196,7 +1269,7 @@ gen_load_llrel(offset, size) sappend(s, s2); } else { s = new_stmt(BPF_LD|BPF_ABS|size); - s->s.k = offset; + s->s.k = offset + off_ll; } return s; } @@ -1214,11 +1287,12 @@ gen_load_a(offrel, offset, size) switch (offrel) { case OR_PACKET: - s = gen_load_llrel(offset, size); + s = new_stmt(BPF_LD|BPF_ABS|size); + s->s.k = offset; break; case OR_LINK: - s = gen_load_llrel(off_ll + offset, size); + s = gen_load_llrel(offset, size); break; case OR_NET: @@ -1821,6 +1895,25 @@ gen_linktype(proto) { struct block *b0, *b1, *b2; + /* are we checking MPLS-encapsulated packets? */ + if (label_stack_depth > 0) { + switch (proto) { + case ETHERTYPE_IP: + case PPP_IP: + /* FIXME add other L3 proto IDs */ + return gen_mpls_linktype(Q_IP); + + case ETHERTYPE_IPV6: + case PPP_IPV6: + /* FIXME add other L3 proto IDs */ + return gen_mpls_linktype(Q_IPV6); + + default: + bpf_error("unsupported protocol over mpls"); + /* NOTREACHED */ + } + } + switch (linktype) { case DLT_EN10MB: @@ -2210,6 +2303,7 @@ gen_linktype(proto) /*NOTREACHED*/ break; + case DLT_JUNIPER_MFR: case DLT_JUNIPER_MLFR: case DLT_JUNIPER_MLPPP: case DLT_JUNIPER_ATM1: @@ -2220,6 +2314,10 @@ gen_linktype(proto) case DLT_JUNIPER_ES: case DLT_JUNIPER_MONITOR: case DLT_JUNIPER_SERVICES: + case DLT_JUNIPER_ETHER: + case DLT_JUNIPER_PPP: + case DLT_JUNIPER_FRELAY: + case DLT_JUNIPER_CHDLC: /* just lets verify the magic number for now - * on ATM we may have up to 6 different encapsulations on the wire * and need a lot of heuristics to figure out that the payload @@ -3004,24 +3102,69 @@ gen_dnhostop(addr, dir) return b1; } +/* + * Generate a check for IPv4 or IPv6 for MPLS-encapsulated packets; + * test the bottom-of-stack bit, and then check the version number + * field in the IP header. + */ static struct block * -gen_host(addr, mask, proto, dir) +gen_mpls_linktype(proto) + int proto; +{ + struct block *b0, *b1; + + switch (proto) { + + case Q_IP: + /* match the bottom-of-stack bit */ + b0 = gen_mcmp(OR_NET, -2, BPF_B, 0x01, 0x01); + /* match the IPv4 version number */ + b1 = gen_mcmp(OR_NET, 0, BPF_B, 0x40, 0xf0); + gen_and(b0, b1); + return b1; + + case Q_IPV6: + /* match the bottom-of-stack bit */ + b0 = gen_mcmp(OR_NET, -2, BPF_B, 0x01, 0x01); + /* match the IPv4 version number */ + b1 = gen_mcmp(OR_NET, 0, BPF_B, 0x60, 0xf0); + gen_and(b0, b1); + return b1; + + default: + abort(); + } +} + +static struct block * +gen_host(addr, mask, proto, dir, type) bpf_u_int32 addr; bpf_u_int32 mask; int proto; int dir; + int type; { struct block *b0, *b1; + const char *typestr; + + if (type == Q_NET) + typestr = "net"; + else + typestr = "host"; switch (proto) { case Q_DEFAULT: - b0 = gen_host(addr, mask, Q_IP, dir); - if (off_linktype != (u_int)-1) { - b1 = gen_host(addr, mask, Q_ARP, dir); - gen_or(b0, b1); - b0 = gen_host(addr, mask, Q_RARP, dir); - gen_or(b1, b0); + b0 = gen_host(addr, mask, Q_IP, dir, type); + /* + * Only check for non-IPv4 addresses if we're not + * checking MPLS-encapsulated packets. + */ + if (label_stack_depth == 0) { + b1 = gen_host(addr, mask, Q_ARP, dir, type); + gen_or(b0, b1); + b0 = gen_host(addr, mask, Q_RARP, dir, type); + gen_or(b1, b0); } return b0; @@ -3035,28 +3178,28 @@ gen_host(addr, mask, proto, dir) return gen_hostop(addr, mask, dir, ETHERTYPE_ARP, 14, 24); case Q_TCP: - bpf_error("'tcp' modifier applied to host"); + bpf_error("'tcp' modifier applied to %s", typestr); case Q_SCTP: - bpf_error("'sctp' modifier applied to host"); + bpf_error("'sctp' modifier applied to %s", typestr); case Q_UDP: - bpf_error("'udp' modifier applied to host"); + bpf_error("'udp' modifier applied to %s", typestr); case Q_ICMP: - bpf_error("'icmp' modifier applied to host"); + bpf_error("'icmp' modifier applied to %s", typestr); case Q_IGMP: - bpf_error("'igmp' modifier applied to host"); + bpf_error("'igmp' modifier applied to %s", typestr); case Q_IGRP: - bpf_error("'igrp' modifier applied to host"); + bpf_error("'igrp' modifier applied to %s", typestr); case Q_PIM: - bpf_error("'pim' modifier applied to host"); + bpf_error("'pim' modifier applied to %s", typestr); case Q_VRRP: - bpf_error("'vrrp' modifier applied to host"); + bpf_error("'vrrp' modifier applied to %s", typestr); case Q_ATALK: bpf_error("ATALK host filtering not implemented"); @@ -3084,38 +3227,38 @@ gen_host(addr, mask, proto, dir) bpf_error("'ip6' modifier applied to ip host"); case Q_ICMPV6: - bpf_error("'icmp6' modifier applied to host"); + bpf_error("'icmp6' modifier applied to %s", typestr); #endif /* INET6 */ case Q_AH: - bpf_error("'ah' modifier applied to host"); + bpf_error("'ah' modifier applied to %s", typestr); case Q_ESP: - bpf_error("'esp' modifier applied to host"); + bpf_error("'esp' modifier applied to %s", typestr); case Q_ISO: bpf_error("ISO host filtering not implemented"); case Q_ESIS: - bpf_error("'esis' modifier applied to host"); + bpf_error("'esis' modifier applied to %s", typestr); case Q_ISIS: - bpf_error("'isis' modifier applied to host"); + bpf_error("'isis' modifier applied to %s", typestr); case Q_CLNP: - bpf_error("'clnp' modifier applied to host"); + bpf_error("'clnp' modifier applied to %s", typestr); case Q_STP: - bpf_error("'stp' modifier applied to host"); + bpf_error("'stp' modifier applied to %s", typestr); case Q_IPX: bpf_error("IPX host filtering not implemented"); case Q_NETBEUI: - bpf_error("'netbeui' modifier applied to host"); + bpf_error("'netbeui' modifier applied to %s", typestr); case Q_RADIO: - bpf_error("'radio' modifier applied to host"); + bpf_error("'radio' modifier applied to %s", typestr); default: abort(); @@ -3125,49 +3268,57 @@ gen_host(addr, mask, proto, dir) #ifdef INET6 static struct block * -gen_host6(addr, mask, proto, dir) +gen_host6(addr, mask, proto, dir, type) struct in6_addr *addr; struct in6_addr *mask; int proto; int dir; + int type; { + const char *typestr; + + if (type == Q_NET) + typestr = "net"; + else + typestr = "host"; + switch (proto) { case Q_DEFAULT: - return gen_host6(addr, mask, Q_IPV6, dir); + return gen_host6(addr, mask, Q_IPV6, dir, type); case Q_IP: - bpf_error("'ip' modifier applied to ip6 host"); + bpf_error("'ip' modifier applied to ip6 %s", typestr); case Q_RARP: - bpf_error("'rarp' modifier applied to ip6 host"); + bpf_error("'rarp' modifier applied to ip6 %s", typestr); case Q_ARP: - bpf_error("'arp' modifier applied to ip6 host"); + bpf_error("'arp' modifier applied to ip6 %s", typestr); case Q_SCTP: - bpf_error("'sctp' modifier applied to host"); + bpf_error("'sctp' modifier applied to %s", typestr); case Q_TCP: - bpf_error("'tcp' modifier applied to host"); + bpf_error("'tcp' modifier applied to %s", typestr); case Q_UDP: - bpf_error("'udp' modifier applied to host"); + bpf_error("'udp' modifier applied to %s", typestr); case Q_ICMP: - bpf_error("'icmp' modifier applied to host"); + bpf_error("'icmp' modifier applied to %s", typestr); case Q_IGMP: - bpf_error("'igmp' modifier applied to host"); + bpf_error("'igmp' modifier applied to %s", typestr); case Q_IGRP: - bpf_error("'igrp' modifier applied to host"); + bpf_error("'igrp' modifier applied to %s", typestr); case Q_PIM: - bpf_error("'pim' modifier applied to host"); + bpf_error("'pim' modifier applied to %s", typestr); case Q_VRRP: - bpf_error("'vrrp' modifier applied to host"); + bpf_error("'vrrp' modifier applied to %s", typestr); case Q_ATALK: bpf_error("ATALK host filtering not implemented"); @@ -3176,7 +3327,7 @@ gen_host6(addr, mask, proto, dir) bpf_error("AARP host filtering not implemented"); case Q_DECNET: - bpf_error("'decnet' modifier applied to ip6 host"); + bpf_error("'decnet' modifier applied to ip6 %s", typestr); case Q_SCA: bpf_error("SCA host filtering not implemented"); @@ -3194,37 +3345,37 @@ gen_host6(addr, mask, proto, dir) return gen_hostop6(addr, mask, dir, ETHERTYPE_IPV6, 8, 24); case Q_ICMPV6: - bpf_error("'icmp6' modifier applied to host"); + bpf_error("'icmp6' modifier applied to %s", typestr); case Q_AH: - bpf_error("'ah' modifier applied to host"); + bpf_error("'ah' modifier applied to %s", typestr); case Q_ESP: - bpf_error("'esp' modifier applied to host"); + bpf_error("'esp' modifier applied to %s", typestr); case Q_ISO: bpf_error("ISO host filtering not implemented"); case Q_ESIS: - bpf_error("'esis' modifier applied to host"); + bpf_error("'esis' modifier applied to %s", typestr); case Q_ISIS: - bpf_error("'isis' modifier applied to host"); + bpf_error("'isis' modifier applied to %s", typestr); case Q_CLNP: - bpf_error("'clnp' modifier applied to host"); + bpf_error("'clnp' modifier applied to %s", typestr); case Q_STP: - bpf_error("'stp' modifier applied to host"); + bpf_error("'stp' modifier applied to %s", typestr); case Q_IPX: bpf_error("IPX host filtering not implemented"); case Q_NETBEUI: - bpf_error("'netbeui' modifier applied to host"); + bpf_error("'netbeui' modifier applied to %s", typestr); case Q_RADIO: - bpf_error("'radio' modifier applied to host"); + bpf_error("'radio' modifier applied to %s", typestr); default: abort(); @@ -3251,18 +3402,24 @@ gen_gateway(eaddr, alist, proto, dir) case Q_IP: case Q_ARP: case Q_RARP: - if (linktype == DLT_EN10MB) - b0 = gen_ehostop(eaddr, Q_OR); - else if (linktype == DLT_FDDI) - b0 = gen_fhostop(eaddr, Q_OR); - else if (linktype == DLT_IEEE802) - b0 = gen_thostop(eaddr, Q_OR); - else if (linktype == DLT_IEEE802_11 || - linktype == DLT_IEEE802_11_RADIO_AVS || - linktype == DLT_IEEE802_11_RADIO || - linktype == DLT_PRISM_HEADER) - b0 = gen_wlanhostop(eaddr, Q_OR); - else if (linktype == DLT_SUNATM && is_lane) { + switch (linktype) { + case DLT_EN10MB: + b0 = gen_ehostop(eaddr, Q_OR); + break; + case DLT_FDDI: + b0 = gen_fhostop(eaddr, Q_OR); + break; + case DLT_IEEE802: + b0 = gen_thostop(eaddr, Q_OR); + break; + case DLT_IEEE802_11: + case DLT_IEEE802_11_RADIO_AVS: + case DLT_IEEE802_11_RADIO: + case DLT_PRISM_HEADER: + b0 = gen_wlanhostop(eaddr, Q_OR); + break; + case DLT_SUNATM: + if (is_lane) { /* * Check that the packet doesn't begin with an * LE Control marker. (We've already generated @@ -3277,15 +3434,19 @@ gen_gateway(eaddr, alist, proto, dir) */ b0 = gen_ehostop(eaddr, Q_OR); gen_and(b1, b0); - } else if (linktype == DLT_IP_OVER_FC) - b0 = gen_ipfchostop(eaddr, Q_OR); - else - bpf_error( + } + break; + case DLT_IP_OVER_FC: + b0 = gen_ipfchostop(eaddr, Q_OR); + break; + default: + bpf_error( "'gateway' supported only on ethernet/FDDI/token ring/802.11/Fibre Channel"); - - b1 = gen_host(**alist++, 0xffffffff, proto, Q_OR); + } + b1 = gen_host(**alist++, 0xffffffff, proto, Q_OR, Q_HOST); while (*alist) { - tmp = gen_host(**alist++, 0xffffffff, proto, Q_OR); + tmp = gen_host(**alist++, 0xffffffff, proto, Q_OR, + Q_HOST); gen_or(b1, tmp); b1 = tmp; } @@ -4363,6 +4524,7 @@ gen_proto(v, proto, dir) * * So we always check for ETHERTYPE_IP. */ + b0 = gen_linktype(ETHERTYPE_IP); #ifndef CHASE_CHAIN b1 = gen_cmp(OR_NET, 9, BPF_B, (bpf_int32)v); @@ -4568,7 +4730,7 @@ gen_scode(name, q) addr <<= 8; mask <<= 8; } - return gen_host(addr, mask, proto, dir); + return gen_host(addr, mask, proto, dir, q.addr); case Q_DEFAULT: case Q_HOST: @@ -4653,7 +4815,7 @@ gen_scode(name, q) * I don't think DECNET hosts can be multihomed, so * there is no need to build up a list of addresses */ - return (gen_host(dn_addr, 0, proto, dir)); + return (gen_host(dn_addr, 0, proto, dir, q.addr)); } else { #ifndef INET6 alist = pcap_nametoaddr(name); @@ -4662,10 +4824,10 @@ gen_scode(name, q) tproto = proto; if (off_linktype == (u_int)-1 && tproto == Q_DEFAULT) tproto = Q_IP; - b = gen_host(**alist++, 0xffffffff, tproto, dir); + b = gen_host(**alist++, 0xffffffff, tproto, dir, q.addr); while (*alist) { tmp = gen_host(**alist++, 0xffffffff, - tproto, dir); + tproto, dir, q.addr); gen_or(b, tmp); b = tmp; } @@ -4690,7 +4852,7 @@ gen_scode(name, q) sin = (struct sockaddr_in *) res->ai_addr; tmp = gen_host(ntohl(sin->sin_addr.s_addr), - 0xffffffff, tproto, dir); + 0xffffffff, tproto, dir, q.addr); break; case AF_INET6: if (tproto6 == Q_IP) @@ -4699,7 +4861,7 @@ gen_scode(name, q) sin6 = (struct sockaddr_in6 *) res->ai_addr; tmp = gen_host6(&sin6->sin6_addr, - &mask128, tproto6, dir); + &mask128, tproto6, dir, q.addr); break; default: continue; @@ -4872,7 +5034,14 @@ gen_mcode(s1, s2, masklen, q) /* Convert mask len to mask */ if (masklen > 32) bpf_error("mask length must be <= 32"); - m = 0xffffffff << (32 - masklen); + if (masklen == 0) { + /* + * X << 32 is not guaranteed by C to be 0; it's + * undefined. + */ + m = 0; + } else + m = 0xffffffff << (32 - masklen); if ((n & ~m) != 0) bpf_error("non-network bits set in \"%s/%d\"", s1, masklen); @@ -4881,7 +5050,7 @@ gen_mcode(s1, s2, masklen, q) switch (q.addr) { case Q_NET: - return gen_host(n, m, q.proto, q.dir); + return gen_host(n, m, q.proto, q.dir, q.addr); default: bpf_error("Mask syntax for networks only"); @@ -4914,7 +5083,7 @@ gen_ncode(s, v, q) case Q_HOST: case Q_NET: if (proto == Q_DECNET) - return gen_host(v, 0, proto, dir); + return gen_host(v, 0, proto, dir, q.addr); else if (proto == Q_LINK) { bpf_error("illegal link layer address"); } else { @@ -4930,7 +5099,7 @@ gen_ncode(s, v, q) v <<= 32 - vlen; mask <<= 32 - vlen; } - return gen_host(v, mask, proto, dir); + return gen_host(v, mask, proto, dir, q.addr); } case Q_PORT: @@ -5048,7 +5217,7 @@ gen_mcode6(s1, s2, masklen, q) /* FALLTHROUGH */ case Q_NET: - b = gen_host6(addr, &mask, q.proto, q.dir); + b = gen_host6(addr, &mask, q.proto, q.dir, q.addr); freeaddrinfo(res); return b; @@ -5067,18 +5236,20 @@ gen_ecode(eaddr, q) struct block *b, *tmp; if ((q.addr == Q_HOST || q.addr == Q_DEFAULT) && q.proto == Q_LINK) { - if (linktype == DLT_EN10MB) - return gen_ehostop(eaddr, (int)q.dir); - if (linktype == DLT_FDDI) - return gen_fhostop(eaddr, (int)q.dir); - if (linktype == DLT_IEEE802) - return gen_thostop(eaddr, (int)q.dir); - if (linktype == DLT_IEEE802_11 || - linktype == DLT_IEEE802_11_RADIO_AVS || - linktype == DLT_IEEE802_11_RADIO || - linktype == DLT_PRISM_HEADER) - return gen_wlanhostop(eaddr, (int)q.dir); - if (linktype == DLT_SUNATM && is_lane) { + switch (linktype) { + case DLT_EN10MB: + return gen_ehostop(eaddr, (int)q.dir); + case DLT_FDDI: + return gen_fhostop(eaddr, (int)q.dir); + case DLT_IEEE802: + return gen_thostop(eaddr, (int)q.dir); + case DLT_IEEE802_11: + case DLT_IEEE802_11_RADIO_AVS: + case DLT_IEEE802_11_RADIO: + case DLT_PRISM_HEADER: + return gen_wlanhostop(eaddr, (int)q.dir); + case DLT_SUNATM: + if (is_lane) { /* * Check that the packet doesn't begin with an * LE Control marker. (We've already generated @@ -5095,9 +5266,13 @@ gen_ecode(eaddr, q) gen_and(tmp, b); return b; } - if (linktype == DLT_IP_OVER_FC) - return gen_ipfchostop(eaddr, (int)q.dir); + break; + case DLT_IP_OVER_FC: + return gen_ipfchostop(eaddr, (int)q.dir); + default: bpf_error("ethernet addresses supported only on ethernet/FDDI/token ring/802.11/ATM LANE/Fibre Channel"); + break; + } } bpf_error("ethernet address used in non-ether expression"); /* NOTREACHED */ @@ -5632,22 +5807,25 @@ gen_broadcast(proto) case Q_DEFAULT: case Q_LINK: - if (linktype == DLT_ARCNET || linktype == DLT_ARCNET_LINUX) - return gen_ahostop(abroadcast, Q_DST); - if (linktype == DLT_EN10MB) - return gen_ehostop(ebroadcast, Q_DST); - if (linktype == DLT_FDDI) - return gen_fhostop(ebroadcast, Q_DST); - if (linktype == DLT_IEEE802) - return gen_thostop(ebroadcast, Q_DST); - if (linktype == DLT_IEEE802_11 || - linktype == DLT_IEEE802_11_RADIO_AVS || - linktype == DLT_IEEE802_11_RADIO || - linktype == DLT_PRISM_HEADER) - return gen_wlanhostop(ebroadcast, Q_DST); - if (linktype == DLT_IP_OVER_FC) - return gen_ipfchostop(ebroadcast, Q_DST); - if (linktype == DLT_SUNATM && is_lane) { + switch (linktype) { + case DLT_ARCNET: + case DLT_ARCNET_LINUX: + return gen_ahostop(abroadcast, Q_DST); + case DLT_EN10MB: + return gen_ehostop(ebroadcast, Q_DST); + case DLT_FDDI: + return gen_fhostop(ebroadcast, Q_DST); + case DLT_IEEE802: + return gen_thostop(ebroadcast, Q_DST); + case DLT_IEEE802_11: + case DLT_IEEE802_11_RADIO_AVS: + case DLT_IEEE802_11_RADIO: + case DLT_PRISM_HEADER: + return gen_wlanhostop(ebroadcast, Q_DST); + case DLT_IP_OVER_FC: + return gen_ipfchostop(ebroadcast, Q_DST); + case DLT_SUNATM: + if (is_lane) { /* * Check that the packet doesn't begin with an * LE Control marker. (We've already generated @@ -5663,8 +5841,11 @@ gen_broadcast(proto) b0 = gen_ehostop(ebroadcast, Q_DST); gen_and(b1, b0); return b0; - } - bpf_error("not a broadcast link"); + } + break; + default: + bpf_error("not a broadcast link"); + } break; case Q_IP: @@ -5711,154 +5892,146 @@ gen_multicast(proto) case Q_DEFAULT: case Q_LINK: - if (linktype == DLT_ARCNET || linktype == DLT_ARCNET_LINUX) - /* all ARCnet multicasts use the same address */ - return gen_ahostop(abroadcast, Q_DST); - - if (linktype == DLT_EN10MB) { - /* ether[0] & 1 != 0 */ - return gen_mac_multicast(0); - } - - if (linktype == DLT_FDDI) { - /* - * XXX TEST THIS: MIGHT NOT PORT PROPERLY XXX - * - * XXX - was that referring to bit-order issues? - */ - /* fddi[1] & 1 != 0 */ - return gen_mac_multicast(1); - } - - if (linktype == DLT_IEEE802) { - /* tr[2] & 1 != 0 */ - return gen_mac_multicast(2); - } - - if (linktype == DLT_IEEE802_11 || - linktype == DLT_IEEE802_11_RADIO_AVS || - linktype == DLT_IEEE802_11_RADIO || - linktype == DLT_PRISM_HEADER) { - /* - * Oh, yuk. - * - * For control frames, there is no DA. - * - * For management frames, DA is at an - * offset of 4 from the beginning of - * the packet. - * - * For data frames, DA is at an offset - * of 4 from the beginning of the packet - * if To DS is clear and at an offset of - * 16 from the beginning of the packet - * if To DS is set. - */ - - /* - * Generate the tests to be done for data frames. - * - * First, check for To DS set, i.e. "link[1] & 0x01". - */ - s = gen_load_a(OR_LINK, 1, BPF_B); - b1 = new_block(JMP(BPF_JSET)); - b1->s.k = 0x01; /* To DS */ - b1->stmts = s; - - /* - * If To DS is set, the DA is at 16. - */ - b0 = gen_mac_multicast(16); - gen_and(b1, b0); - - /* - * Now, check for To DS not set, i.e. check - * "!(link[1] & 0x01)". - */ - s = gen_load_a(OR_LINK, 1, BPF_B); - b2 = new_block(JMP(BPF_JSET)); - b2->s.k = 0x01; /* To DS */ - b2->stmts = s; - gen_not(b2); - - /* - * If To DS is not set, the DA is at 4. - */ - b1 = gen_mac_multicast(4); - gen_and(b2, b1); - - /* - * Now OR together the last two checks. That gives - * the complete set of checks for data frames. - */ - gen_or(b1, b0); - - /* - * Now check for a data frame. - * I.e, check "link[0] & 0x08". - */ - s = gen_load_a(OR_LINK, 0, BPF_B); - b1 = new_block(JMP(BPF_JSET)); - b1->s.k = 0x08; - b1->stmts = s; - - /* - * AND that with the checks done for data frames. - */ - gen_and(b1, b0); - - /* - * If the high-order bit of the type value is 0, this - * is a management frame. - * I.e, check "!(link[0] & 0x08)". - */ - s = gen_load_a(OR_LINK, 0, BPF_B); - b2 = new_block(JMP(BPF_JSET)); - b2->s.k = 0x08; - b2->stmts = s; - gen_not(b2); - - /* - * For management frames, the DA is at 4. - */ - b1 = gen_mac_multicast(4); - gen_and(b2, b1); - - /* - * OR that with the checks done for data frames. - * That gives the checks done for management and - * data frames. - */ - gen_or(b1, b0); - - /* - * If the low-order bit of the type value is 1, - * this is either a control frame or a frame - * with a reserved type, and thus not a - * frame with an SA. - * - * I.e., check "!(link[0] & 0x04)". - */ - s = gen_load_a(OR_LINK, 0, BPF_B); - b1 = new_block(JMP(BPF_JSET)); - b1->s.k = 0x04; - b1->stmts = s; - gen_not(b1); - - /* - * AND that with the checks for data and management - * frames. - */ - gen_and(b1, b0); - return b0; - } - - if (linktype == DLT_IP_OVER_FC) { - b0 = gen_mac_multicast(2); - return b0; - } - - if (linktype == DLT_SUNATM && is_lane) { + switch (linktype) { + case DLT_ARCNET: + case DLT_ARCNET_LINUX: + /* all ARCnet multicasts use the same address */ + return gen_ahostop(abroadcast, Q_DST); + case DLT_EN10MB: + /* ether[0] & 1 != 0 */ + return gen_mac_multicast(0); + case DLT_FDDI: + /* + * XXX TEST THIS: MIGHT NOT PORT PROPERLY XXX + * + * XXX - was that referring to bit-order issues? + */ + /* fddi[1] & 1 != 0 */ + return gen_mac_multicast(1); + case DLT_IEEE802: + /* tr[2] & 1 != 0 */ + return gen_mac_multicast(2); + case DLT_IEEE802_11: + case DLT_IEEE802_11_RADIO_AVS: + case DLT_IEEE802_11_RADIO: + case DLT_PRISM_HEADER: + /* + * Oh, yuk. + * + * For control frames, there is no DA. + * + * For management frames, DA is at an + * offset of 4 from the beginning of + * the packet. + * + * For data frames, DA is at an offset + * of 4 from the beginning of the packet + * if To DS is clear and at an offset of + * 16 from the beginning of the packet + * if To DS is set. + */ + + /* + * Generate the tests to be done for data frames. + * + * First, check for To DS set, i.e. "link[1] & 0x01". + */ + s = gen_load_a(OR_LINK, 1, BPF_B); + b1 = new_block(JMP(BPF_JSET)); + b1->s.k = 0x01; /* To DS */ + b1->stmts = s; + + /* + * If To DS is set, the DA is at 16. + */ + b0 = gen_mac_multicast(16); + gen_and(b1, b0); + + /* + * Now, check for To DS not set, i.e. check + * "!(link[1] & 0x01)". + */ + s = gen_load_a(OR_LINK, 1, BPF_B); + b2 = new_block(JMP(BPF_JSET)); + b2->s.k = 0x01; /* To DS */ + b2->stmts = s; + gen_not(b2); + + /* + * If To DS is not set, the DA is at 4. + */ + b1 = gen_mac_multicast(4); + gen_and(b2, b1); + + /* + * Now OR together the last two checks. That gives + * the complete set of checks for data frames. + */ + gen_or(b1, b0); + + /* + * Now check for a data frame. + * I.e, check "link[0] & 0x08". + */ + s = gen_load_a(OR_LINK, 0, BPF_B); + b1 = new_block(JMP(BPF_JSET)); + b1->s.k = 0x08; + b1->stmts = s; + + /* + * AND that with the checks done for data frames. + */ + gen_and(b1, b0); + + /* + * If the high-order bit of the type value is 0, this + * is a management frame. + * I.e, check "!(link[0] & 0x08)". + */ + s = gen_load_a(OR_LINK, 0, BPF_B); + b2 = new_block(JMP(BPF_JSET)); + b2->s.k = 0x08; + b2->stmts = s; + gen_not(b2); + + /* + * For management frames, the DA is at 4. + */ + b1 = gen_mac_multicast(4); + gen_and(b2, b1); + + /* + * OR that with the checks done for data frames. + * That gives the checks done for management and + * data frames. + */ + gen_or(b1, b0); + + /* + * If the low-order bit of the type value is 1, + * this is either a control frame or a frame + * with a reserved type, and thus not a + * frame with an SA. + * + * I.e., check "!(link[0] & 0x04)". + */ + s = gen_load_a(OR_LINK, 0, BPF_B); + b1 = new_block(JMP(BPF_JSET)); + b1->s.k = 0x04; + b1->stmts = s; + gen_not(b1); + + /* + * AND that with the checks for data and management + * frames. + */ + gen_and(b1, b0); + return b0; + case DLT_IP_OVER_FC: + b0 = gen_mac_multicast(2); + return b0; + case DLT_SUNATM: + if (is_lane) { /* * Check that the packet doesn't begin with an * LE Control marker. (We've already generated @@ -5872,10 +6045,13 @@ gen_multicast(proto) b0 = gen_mac_multicast(off_mac); gen_and(b1, b0); return b0; - } - - /* Link not known to support multicasts */ - break; + } + break; + default: + break; + } + /* Link not known to support multicasts */ + break; case Q_IP: b0 = gen_linktype(ETHERTYPE_IP); @@ -5953,6 +6129,7 @@ gen_inbound(dir) } break; + case DLT_JUNIPER_MFR: case DLT_JUNIPER_MLFR: case DLT_JUNIPER_MLPPP: case DLT_JUNIPER_ATM1: @@ -5963,6 +6140,10 @@ gen_inbound(dir) case DLT_JUNIPER_ES: case DLT_JUNIPER_MONITOR: case DLT_JUNIPER_SERVICES: + case DLT_JUNIPER_ETHER: + case DLT_JUNIPER_PPP: + case DLT_JUNIPER_FRELAY: + case DLT_JUNIPER_CHDLC: /* juniper flags (including direction) are stored * the byte after the 3-byte magic number */ if (dir) { @@ -6006,7 +6187,7 @@ gen_pf_ifname(const char *ifname) return (b0); } -/* PF firewall log matched interface */ +/* PF firewall log ruleset name */ struct block * gen_pf_ruleset(char *ruleset) { @@ -6145,7 +6326,11 @@ struct block * gen_vlan(vlan_num) int vlan_num; { - struct block *b0; + struct block *b0, *b1; + + /* can't check for VLAN-encapsulated packets inside MPLS */ + if (label_stack_depth > 0) + bpf_error("no VLAN match after MPLS"); /* * Change the offsets to point to the type and data fields within @@ -6177,30 +6362,28 @@ gen_vlan(vlan_num) * be done assuming a VLAN, even though the "or" could be viewed * as meaning "or, if this isn't a VLAN packet...". */ - orig_linktype = off_linktype; /* save original values */ - orig_nl = off_nl; + orig_linktype = off_linktype; /* save original values */ + orig_nl = off_nl; - switch (linktype) { + switch (linktype) { - case DLT_EN10MB: - off_linktype += 4; - off_nl_nosnap += 4; - off_nl += 4; - break; + case DLT_EN10MB: + off_linktype += 4; + off_nl_nosnap += 4; + off_nl += 4; + break; - default: - bpf_error("no VLAN support for data link type %d", - linktype); - /*NOTREACHED*/ - } + default: + bpf_error("no VLAN support for data link type %d", + linktype); + /*NOTREACHED*/ + } /* check for VLAN */ b0 = gen_cmp(OR_LINK, orig_linktype, BPF_H, (bpf_int32)ETHERTYPE_8021Q); /* If a specific VLAN is requested, check VLAN id */ if (vlan_num >= 0) { - struct block *b1; - b1 = gen_mcmp(OR_LINK, orig_nl, BPF_H, (bpf_int32)vlan_num, 0x0fff); gen_and(b0, b1); @@ -6217,7 +6400,7 @@ struct block * gen_mpls(label_num) int label_num; { - struct block *b0; + struct block *b0,*b1; /* * Change the offsets to point to the type and data fields within @@ -6228,46 +6411,46 @@ gen_mpls(label_num) * * XXX - this is a bit of a kludge. See comments in gen_vlan(). */ - orig_linktype = off_linktype; /* save original values */ orig_nl = off_nl; - switch (linktype) { - - case DLT_C_HDLC: /* fall through */ - case DLT_EN10MB: - off_linktype += 4; - off_nl_nosnap += 4; - off_nl += 4; - - b0 = gen_cmp(OR_LINK, orig_linktype, BPF_H, - (bpf_int32)ETHERTYPE_MPLS); - break; - - case DLT_PPP: - off_linktype += 4; - off_nl_nosnap += 4; - off_nl += 4; - - b0 = gen_cmp(OR_LINK, orig_linktype, BPF_H, - (bpf_int32)PPP_MPLS_UCAST); - break; - - /* FIXME add other DLT_s ... - * for Frame-Relay/and ATM this may get messy due to SNAP headers - * leave it for now */ - - default: - bpf_error("no MPLS support for data link type %d", + if (label_stack_depth > 0) { + /* just match the bottom-of-stack bit clear */ + b0 = gen_mcmp(OR_LINK, orig_nl-2, BPF_B, 0, 0x01); + } else { + /* + * Indicate that we're checking MPLS-encapsulated headers, + * to make sure higher level code generators don't try to + * match against IP-related protocols such as Q_ARP, Q_RARP + * etc. + */ + switch (linktype) { + + case DLT_C_HDLC: /* fall through */ + case DLT_EN10MB: + b0 = gen_cmp(OR_LINK, off_linktype, BPF_H, + (bpf_int32)ETHERTYPE_MPLS); + break; + + case DLT_PPP: + b0 = gen_cmp(OR_LINK, off_linktype, BPF_H, + (bpf_int32)PPP_MPLS_UCAST); + break; + + /* FIXME add other DLT_s ... + * for Frame-Relay/and ATM this may get messy due to SNAP headers + * leave it for now */ + + default: + bpf_error("no MPLS support for data link type %d", linktype); - b0 = NULL; - /*NOTREACHED*/ - break; + b0 = NULL; + /*NOTREACHED*/ + break; + } } /* If a specific MPLS label is requested, check it */ if (label_num >= 0) { - struct block *b1; - label_num = label_num << 12; /* label is shifted 12 bits on the wire */ b1 = gen_mcmp(OR_LINK, orig_nl, BPF_W, (bpf_int32)label_num, 0xfffff000); /* only compare the first 20 bits */ @@ -6275,9 +6458,84 @@ gen_mpls(label_num) b0 = b1; } + off_nl_nosnap += 4; + off_nl += 4; + label_stack_depth++; return (b0); } +/* + * Support PPPOE discovery and session. + */ +struct block * +gen_pppoed() +{ + /* check for PPPoE discovery */ + return gen_linktype((bpf_int32)ETHERTYPE_PPPOED); +} + +struct block * +gen_pppoes() +{ + struct block *b0; + + /* + * Test against the PPPoE session link-layer type. + */ + b0 = gen_linktype((bpf_int32)ETHERTYPE_PPPOES); + + /* + * Change the offsets to point to the type and data fields within + * the PPP packet. + * + * XXX - this is a bit of a kludge. If we were to split the + * compiler into a parser that parses an expression and + * generates an expression tree, and a code generator that + * takes an expression tree (which could come from our + * parser or from some other parser) and generates BPF code, + * we could perhaps make the offsets parameters of routines + * and, in the handler for an "AND" node, pass to subnodes + * other than the PPPoE node the adjusted offsets. + * + * This would mean that "pppoes" would, instead of changing the + * behavior of *all* tests after it, change only the behavior + * of tests ANDed with it. That would change the documented + * semantics of "pppoes", which might break some expressions. + * However, it would mean that "(pppoes and ip) or ip" would check + * both for VLAN-encapsulated IP and IP-over-Ethernet, rather than + * checking only for VLAN-encapsulated IP, so that could still + * be considered worth doing; it wouldn't break expressions + * that are of the form "pppoes and ..." which I suspect are the + * most common expressions involving "pppoes". "pppoes or ..." + * doesn't necessarily do what the user would really want, now, + * as all the "or ..." tests would be done assuming PPPoE, even + * though the "or" could be viewed as meaning "or, if this isn't + * a PPPoE packet...". + */ + orig_linktype = off_linktype; /* save original values */ + orig_nl = off_nl; + + /* + * The "network-layer" protocol is PPPoE, which has a 6-byte + * PPPoE header, followed by PPP payload, so we set the + * offsets to the network layer offset plus 6 bytes for + * the PPPoE header plus the values appropriate for PPP when + * encapsulated in Ethernet (which means there's no HDLC + * encapsulation). + */ + off_linktype = orig_nl + 6; + off_nl = orig_nl + 6 + 2; + off_nl_nosnap = orig_nl + 6 + 2; + + /* + * Set the link-layer type to PPP, as all subsequent tests will + * be on the encapsulated PPP header. + */ + linktype = DLT_PPP; + + return b0; +} + struct block * gen_atmfield_code(atmfield, jvalue, jtype, reverse) int atmfield; @@ -6437,6 +6695,86 @@ gen_atmtype_abbrev(type) return b1; } +struct block * +gen_mtp3field_code(mtp3field, jvalue, jtype, reverse) + int mtp3field; + bpf_u_int32 jvalue; + bpf_u_int32 jtype; + int reverse; +{ + struct block *b0; + bpf_u_int32 val1 , val2 , val3; + + switch (mtp3field) { + + case M_SIO: + if (off_sio == (u_int)-1) + bpf_error("'sio' supported only on SS7"); + /* sio coded on 1 byte so max value 255 */ + if(jvalue > 255) + bpf_error("sio value %u too big; max value = 255", + jvalue); + b0 = gen_ncmp(OR_PACKET, off_sio, BPF_B, 0xffffffff, + (u_int)jtype, reverse, (u_int)jvalue); + break; + + case M_OPC: + if (off_opc == (u_int)-1) + bpf_error("'opc' supported only on SS7"); + /* opc coded on 14 bits so max value 16383 */ + if (jvalue > 16383) + bpf_error("opc value %u too big; max value = 16383", + jvalue); + /* the following instructions are made to convert jvalue + * to the form used to write opc in an ss7 message*/ + val1 = jvalue & 0x00003c00; + val1 = val1 >>10; + val2 = jvalue & 0x000003fc; + val2 = val2 <<6; + val3 = jvalue & 0x00000003; + val3 = val3 <<22; + jvalue = val1 + val2 + val3; + b0 = gen_ncmp(OR_PACKET, off_opc, BPF_W, 0x00c0ff0f, + (u_int)jtype, reverse, (u_int)jvalue); + break; + + case M_DPC: + if (off_dpc == (u_int)-1) + bpf_error("'dpc' supported only on SS7"); + /* dpc coded on 14 bits so max value 16383 */ + if (jvalue > 16383) + bpf_error("dpc value %u too big; max value = 16383", + jvalue); + /* the following instructions are made to convert jvalue + * to the forme used to write dpc in an ss7 message*/ + val1 = jvalue & 0x000000ff; + val1 = val1 << 24; + val2 = jvalue & 0x00003f00; + val2 = val2 << 8; + jvalue = val1 + val2; + b0 = gen_ncmp(OR_PACKET, off_dpc, BPF_W, 0xff3f0000, + (u_int)jtype, reverse, (u_int)jvalue); + break; + + case M_SLS: + if (off_sls == (u_int)-1) + bpf_error("'sls' supported only on SS7"); + /* sls coded on 4 bits so max value 15 */ + if (jvalue > 15) + bpf_error("sls value %u too big; max value = 15", + jvalue); + /* the following instruction is made to convert jvalue + * to the forme used to write sls in an ss7 message*/ + jvalue = jvalue << 4; + b0 = gen_ncmp(OR_PACKET, off_sls, BPF_B, 0xf0, + (u_int)jtype,reverse, (u_int)jvalue); + break; + + default: + abort(); + } + return b0; +} static struct block * gen_msg_abbrev(type)