+
+/*
+ * 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;
+ bpf_int32 jvalue;
+ bpf_u_int32 jtype;
+ int reverse;
+{
+ struct block *b0;
+
+ switch (atmfield) {
+
+ case A_VPI:
+ if (!is_atm)
+ bpf_error("'vpi' supported only on raw ATM");
+ if (off_vpi == (u_int)-1)
+ abort();
+ b0 = gen_ncmp(OR_LINK, off_vpi, BPF_B, 0xffffffff, jtype,
+ reverse, jvalue);
+ break;
+
+ case A_VCI:
+ if (!is_atm)
+ bpf_error("'vci' supported only on raw ATM");
+ if (off_vci == (u_int)-1)
+ abort();
+ b0 = gen_ncmp(OR_LINK, off_vci, BPF_H, 0xffffffff, jtype,
+ reverse, jvalue);
+ break;
+
+ case A_PROTOTYPE:
+ if (off_proto == (u_int)-1)
+ abort(); /* XXX - this isn't on FreeBSD */
+ b0 = gen_ncmp(OR_LINK, off_proto, BPF_B, 0x0f, jtype,
+ reverse, jvalue);
+ break;
+
+ case A_MSGTYPE:
+ if (off_payload == (u_int)-1)
+ abort();
+ b0 = gen_ncmp(OR_LINK, off_payload + MSG_TYPE_POS, BPF_B,
+ 0xffffffff, jtype, reverse, jvalue);
+ break;
+
+ case A_CALLREFTYPE:
+ if (!is_atm)
+ bpf_error("'callref' supported only on raw ATM");
+ if (off_proto == (u_int)-1)
+ abort();
+ b0 = gen_ncmp(OR_LINK, off_proto, BPF_B, 0xffffffff,
+ jtype, reverse, jvalue);
+ break;
+
+ default:
+ abort();
+ }
+ return b0;
+}
+
+struct block *
+gen_atmtype_abbrev(type)
+ int type;
+{
+ struct block *b0, *b1;
+
+ switch (type) {
+
+ case A_METAC:
+ /* Get all packets in Meta signalling Circuit */
+ if (!is_atm)
+ bpf_error("'metac' supported only on raw ATM");
+ b0 = gen_atmfield_code(A_VPI, 0, BPF_JEQ, 0);
+ b1 = gen_atmfield_code(A_VCI, 1, BPF_JEQ, 0);
+ gen_and(b0, b1);
+ break;
+
+ case A_BCC:
+ /* Get all packets in Broadcast Circuit*/
+ if (!is_atm)
+ bpf_error("'bcc' supported only on raw ATM");
+ b0 = gen_atmfield_code(A_VPI, 0, BPF_JEQ, 0);
+ b1 = gen_atmfield_code(A_VCI, 2, BPF_JEQ, 0);
+ gen_and(b0, b1);
+ break;
+
+ case A_OAMF4SC:
+ /* Get all cells in Segment OAM F4 circuit*/
+ if (!is_atm)
+ bpf_error("'oam4sc' supported only on raw ATM");
+ b0 = gen_atmfield_code(A_VPI, 0, BPF_JEQ, 0);
+ b1 = gen_atmfield_code(A_VCI, 3, BPF_JEQ, 0);
+ gen_and(b0, b1);
+ break;
+
+ case A_OAMF4EC:
+ /* Get all cells in End-to-End OAM F4 Circuit*/
+ if (!is_atm)
+ bpf_error("'oam4ec' supported only on raw ATM");
+ b0 = gen_atmfield_code(A_VPI, 0, BPF_JEQ, 0);
+ b1 = gen_atmfield_code(A_VCI, 4, BPF_JEQ, 0);
+ gen_and(b0, b1);
+ break;
+
+ case A_SC:
+ /* Get all packets in connection Signalling Circuit */
+ if (!is_atm)
+ bpf_error("'sc' supported only on raw ATM");
+ b0 = gen_atmfield_code(A_VPI, 0, BPF_JEQ, 0);
+ b1 = gen_atmfield_code(A_VCI, 5, BPF_JEQ, 0);
+ gen_and(b0, b1);
+ break;
+
+ case A_ILMIC:
+ /* Get all packets in ILMI Circuit */
+ if (!is_atm)
+ bpf_error("'ilmic' supported only on raw ATM");
+ b0 = gen_atmfield_code(A_VPI, 0, BPF_JEQ, 0);
+ b1 = gen_atmfield_code(A_VCI, 16, BPF_JEQ, 0);
+ gen_and(b0, b1);
+ break;
+
+ case A_LANE:
+ /* Get all LANE packets */
+ if (!is_atm)
+ bpf_error("'lane' supported only on raw ATM");
+ b1 = gen_atmfield_code(A_PROTOTYPE, PT_LANE, BPF_JEQ, 0);
+
+ /*
+ * Arrange that all subsequent tests assume LANE
+ * rather than LLC-encapsulated packets, and set
+ * the offsets appropriately for LANE-encapsulated
+ * Ethernet.
+ *
+ * "off_mac" is the offset of the Ethernet header,
+ * which is 2 bytes past the ATM pseudo-header
+ * (skipping the pseudo-header and 2-byte LE Client
+ * field). The other offsets are Ethernet offsets
+ * relative to "off_mac".
+ */
+ is_lane = 1;
+ off_mac = off_payload + 2; /* MAC header */
+ off_linktype = off_mac + 12;
+ off_nl = off_mac + 14; /* Ethernet II */
+ off_nl_nosnap = off_mac + 17; /* 802.3+802.2 */
+ break;
+
+ case A_LLC:
+ /* Get all LLC-encapsulated packets */
+ if (!is_atm)
+ bpf_error("'llc' supported only on raw ATM");
+ b1 = gen_atmfield_code(A_PROTOTYPE, PT_LLC, BPF_JEQ, 0);
+ is_lane = 0;
+ break;
+
+ default:
+ abort();
+ }
+ 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)
+ int type;
+{
+ struct block *b1;
+
+ /*
+ * Q.2931 signalling protocol messages for handling virtual circuits
+ * establishment and teardown
+ */
+ switch (type) {
+
+ case A_SETUP:
+ b1 = gen_atmfield_code(A_MSGTYPE, SETUP, BPF_JEQ, 0);
+ break;
+
+ case A_CALLPROCEED:
+ b1 = gen_atmfield_code(A_MSGTYPE, CALL_PROCEED, BPF_JEQ, 0);
+ break;
+
+ case A_CONNECT:
+ b1 = gen_atmfield_code(A_MSGTYPE, CONNECT, BPF_JEQ, 0);
+ break;
+
+ case A_CONNECTACK:
+ b1 = gen_atmfield_code(A_MSGTYPE, CONNECT_ACK, BPF_JEQ, 0);
+ break;
+
+ case A_RELEASE:
+ b1 = gen_atmfield_code(A_MSGTYPE, RELEASE, BPF_JEQ, 0);
+ break;
+
+ case A_RELEASE_DONE:
+ b1 = gen_atmfield_code(A_MSGTYPE, RELEASE_DONE, BPF_JEQ, 0);
+ break;
+
+ default:
+ abort();
+ }
+ return b1;
+}
+
+struct block *
+gen_atmmulti_abbrev(type)
+ int type;
+{
+ struct block *b0, *b1;
+
+ switch (type) {
+
+ case A_OAM:
+ if (!is_atm)
+ bpf_error("'oam' supported only on raw ATM");
+ b1 = gen_atmmulti_abbrev(A_OAMF4);
+ break;
+
+ case A_OAMF4:
+ if (!is_atm)
+ bpf_error("'oamf4' supported only on raw ATM");
+ /* OAM F4 type */
+ b0 = gen_atmfield_code(A_VCI, 3, BPF_JEQ, 0);
+ b1 = gen_atmfield_code(A_VCI, 4, BPF_JEQ, 0);
+ gen_or(b0, b1);
+ b0 = gen_atmfield_code(A_VPI, 0, BPF_JEQ, 0);
+ gen_and(b0, b1);
+ break;
+
+ case A_CONNECTMSG:
+ /*
+ * Get Q.2931 signalling messages for switched
+ * virtual connection
+ */
+ if (!is_atm)
+ bpf_error("'connectmsg' supported only on raw ATM");
+ b0 = gen_msg_abbrev(A_SETUP);
+ b1 = gen_msg_abbrev(A_CALLPROCEED);
+ gen_or(b0, b1);
+ b0 = gen_msg_abbrev(A_CONNECT);
+ gen_or(b0, b1);
+ b0 = gen_msg_abbrev(A_CONNECTACK);
+ gen_or(b0, b1);
+ b0 = gen_msg_abbrev(A_RELEASE);
+ gen_or(b0, b1);
+ b0 = gen_msg_abbrev(A_RELEASE_DONE);
+ gen_or(b0, b1);
+ b0 = gen_atmtype_abbrev(A_SC);
+ gen_and(b0, b1);
+ break;
+
+ case A_METACONNECT:
+ if (!is_atm)
+ bpf_error("'metaconnect' supported only on raw ATM");
+ b0 = gen_msg_abbrev(A_SETUP);
+ b1 = gen_msg_abbrev(A_CALLPROCEED);
+ gen_or(b0, b1);
+ b0 = gen_msg_abbrev(A_CONNECT);
+ gen_or(b0, b1);
+ b0 = gen_msg_abbrev(A_RELEASE);
+ gen_or(b0, b1);
+ b0 = gen_msg_abbrev(A_RELEASE_DONE);
+ gen_or(b0, b1);
+ b0 = gen_atmtype_abbrev(A_METAC);
+ gen_and(b0, b1);
+ break;
+
+ default:
+ abort();
+ }
+ return b1;
+}