[prev in list] [next in list] [prev in thread] [next in thread] 

List:       snort-devel
Subject:    Re: [Snort-devel] [PATCH] Add non-IP layer 3 detection via new
From:       Joshua Kinard <kumba () gentoo ! org>
Date:       2011-12-27 0:06:35
Message-ID: 4EF90C0B.2000104 () gentoo ! org
[Download RAW message or body]

With the release of snort-2.9.2 final, I rebased my work for the ether_type
rule option.  Some of the data types changed which required it.

In addition, I added the bit of code to DecodeIEEE80211Pkt to make it work
with ether_type (no time to fix the mess w/ LLC/SNAP frame decoding right
now), and I added documentation to the snort manual for the new option and
tested it once I got the TeX tools setup and working.

Attached patch only modifies the snort_manual.tex file, so the PDF would
need to be regenerated in an upcoming release if this is accepted.

And lets not forget the hyperlinks in the manual next time :)

Changes:
 doc/snort_manual.tex                            |  105 ++++++
 src/decode.c                                    |  120 +++++++
 src/decode.h                                    |   27 +
 src/detect.c                                    |   42 +-
 src/detection-plugins/Makefile.am               |    3
 src/detection-plugins/Makefile.in               |    8
 src/detection-plugins/detection_options.c       |   14
 src/detection-plugins/sp_ether_type.c           |  361 ++++++++++++++++++++++++
 src/detection-plugins/sp_ether_type.h           |  125 ++++++++
 src/dynamic-plugins/sf_engine/sf_snort_packet.h |    3
 src/fpcreate.c                                  |  252 +++++++++++++---
 src/fpcreate.h                                  |    7
 src/fpdetect.c                                  |  241 ++++++++++------
 src/fpdetect.h                                  |   12
 src/parser.c                                    |  183 ++++++++----
 src/plugbase.c                                  |    2
 src/plugin_enum.h                               |    1
 src/rule_option_types.h                         |    3
 src/sfutil/sfportobject.h                       |    7
 src/snort.c                                     |   14
 src/snort.h                                     |    4
 21 files changed, 1313 insertions(+), 221 deletions(-)


Cheers!

-- 
Joshua Kinard
Gentoo/MIPS
kumba@gentoo.org
4096R/D25D95E3 2011-03-28

"The past tempts us, the present confuses us, the future frightens us.  And
our lives slip away, moment by moment, lost in that vast, terrible in-between."

--Emperor Turhan, Centauri Republic

["snort-2.9.2-ether_type-support.patch" (text/plain)]

diff --git a/doc/snort_manual.tex b/doc/snort_manual.tex
index 23111c0..020415d 100644
--- a/doc/snort_manual.tex
+++ b/doc/snort_manual.tex
@@ -13402,9 +13402,9 @@ database:
 
 \subsection{Protocols}
 
-The next field in a rule is the protocol. There are four protocols that Snort
-currently analyzes for suspicious behavior -- TCP, UDP, ICMP, and IP. In the
-future there may be more, such as ARP, IGRP, GRE, OSPF, RIP, IPX, etc.
+The next field in a rule is the protocol. There are five protocols that Snort
+currently analyzes for suspicious behavior -- TCP, UDP, ICMP, IP, and ETH. In
+the future there may be more, such as SCTP, DCCP, IGRP, GRE, OSPF, RIP, etc.
 
 \subsection{IP Addresses}
 
@@ -16694,6 +16694,104 @@ This example looks for IGMP traffic.
     alert ip any any -> any any (ip_proto:igmp;)
 \end{verbatim}
 
+\subsection{ether\_type}
+
+The ether\_type keyword allows checks against the Ethernet II type.
+
+\subsubsection{Format}
+
+\begin{verbatim}
+    ether_type:[!|>|<] <hex code> | <name>
+\end{verbatim}
+
+Where \texttt{<hex code>} is a value ranging from \texttt{0x0600} to \texttt{0xffff}
+OR where \texttt{<name>} is a value from table \ref{ethertypes}.
+
+\begin{table}[h]
+\begin{center}
+\caption{Named Ethertypes}
+\label{ethertypes}
+
+\begin{tabular}{| l | l | p{2.8in} |}
+\hline
+{\bf Name} & {\bf Value} & {\bf Description}\\
+\hline
+
+\texttt{xerox} & \texttt{0x0600} & Xerox NS IDP\\
+\hline
+\texttt{ipv4} & \texttt{0x0800} & IP version 4\\
+\hline
+\texttt{x75} & \texttt{0x0801} & X.75 Internet\\
+\hline
+\texttt{nbs} & \texttt{0x0802} & NBS Internet\\
+\hline
+\texttt{ecma} & \texttt{0x0803} & ECMA Internet\\
+\hline
+\texttt{chaos} & \texttt{0x0804} & CHAOSNet\\
+\hline
+\texttt{x25} & \texttt{0x0805} & X.25 Level 3\\
+\hline
+\texttt{arp} & \texttt{0x0806} & Address Resolution Protocol\\
+\hline
+\texttt{rarp} & \texttt{0x0835} & Reverse ARP\\
+\hline
+\texttt{wol} & \texttt{0x0842} & Wake On LAN\\
+\hline
+\texttt{ax25} & \texttt{0x08ff} & AX.25 over Ethernet (G8BPQ)\\
+\hline
+\texttt{decnet} & \texttt{0x6003} & DECnet DNA\\
+\hline
+\texttt{apple} & \texttt{0x809b} & Appletalk\\
+\hline
+\texttt{aarp} & \texttt{0x80f3} & Appletalk ARP\\
+\hline
+\texttt{vlan} & \texttt{0x8100} & VLAN Tagged 802.1q\\
+\hline
+\texttt{netbeui} & \texttt{0x8191} & NetBEUI\\
+\hline
+\texttt{ipx} & \texttt{0x8137} & Novell IPX/SPX\\
+\hline
+\texttt{snmp} & \texttt{0x814c} & SNMP over Ethernet\\
+\hline
+\texttt{ipv6} & \texttt{0x86dd} & IP version 6\\
+\hline
+\texttt{slow} & \texttt{0x8809} & Slow Protocols\\
+\hline
+\texttt{ppp} & \texttt{0x880b} & Point-to-Point Protocol\\
+\hline
+\texttt{mpls} & \texttt{0x8847} & MPLS Unicast\\
+\hline
+\texttt{pppoed} & \texttt{0x8863} & PPP over Ethernet Discovery\\
+\hline
+\texttt{pppoes} & \texttt{0x8864} & PPP over Ethernet Session\\
+\hline
+\texttt{eapol} & \texttt{0x888e} & EAPOL (EAP over LAN), IEEE 802.1x\\
+\hline
+\texttt{aoe} & \texttt{0x88a2} & ATA over Ethernet\\
+\hline
+\texttt{lldp} & \texttt{0x88cc} & Logical Link Discovery Protocol\\
+\hline
+\texttt{fcoe} & \texttt{0x8906} & FibreChannel over Ethernet\\
+\hline
+\texttt{fip} & \texttt{0x8914} & FCoE Initialization Protocol\\
+\hline
+\texttt{tte} & \texttt{0x891d} & TTEthernet\\
+\hline
+\texttt{loop} & \texttt{0x9000} & Loopback\\
+\hline
+
+\end{tabular}
+\end{center}
+\end{table}
+
+\subsubsection{Example}
+
+This example looks for a NetWare server named FOOBAR in IPX traffic.
+
+\begin{verbatim}
+    alert eth any any -> any any (ether_type:ipx; content:"FOOBAR";)
+\end{verbatim}
+
 \subsection{sameip}
 
 The sameip keyword allows rules to check if the source ip is the same as the
@@ -17516,6 +17614,7 @@ beginning of any rule:
 
 \begin{itemize}
 \item \texttt{dsize}
+\item \texttt{ether\_type}
 \item \texttt{flags}
 \item \texttt{flow}
 \item \texttt{fragbits}
diff --git a/src/decode.c b/src/decode.c
index 26d4cf4..0d5b349 100644
--- a/src/decode.c
+++ b/src/decode.c
@@ -777,8 +777,21 @@ void DecodeEthPkt(Packet * p, const DAQ_PktHdr_t * pkthdr, const \
uint8_t * pkt)  ntohs(p->eh->ether_type), p->pkth->pktlen)
             );
 
+    /* Set some convienience pointers for eth rules. */
+    p->eth_data = (pkt + sizeof(*p->eh));
+    p->eth_dsize = (uint16_t)(cap_len - ETHERNET_HEADER_LEN);
+    p->eth_type = ntohs(p->eh->ether_type);
+    p->dsize = p->eth_dsize;
+
+    if (ScIdsMode())
+    {
+        /* See if there are any ether_type only rules that match */
+        fpEvalEtherTypeOnlyRules(snort_conf->eth_type_only_lists, p);
+        p->proto_bits |= PROTO_BIT__ETH_II;
+    }
+
     /* grab out the network type */
-    switch(ntohs(p->eh->ether_type))
+    switch(p->eth_type)
     {
         case ETHERNET_TYPE_IP:
             DEBUG_WRAP(
@@ -891,7 +904,20 @@ void DecodeTransBridging(const uint8_t *pkt, const uint32_t len, \
Packet *p)  p->eh = (EtherHdr *)pkt;
     PushLayer(PROTO_ETH, p, pkt, sizeof(*p->eh));
 
-    switch (ntohs(p->eh->ether_type))
+    /* Set some convienience pointers for eth rules. */
+    p->eth_data = (pkt + sizeof(*p->eh));
+    p->eth_dsize = (uint16_t)(len - ETHERNET_HEADER_LEN);
+    p->eth_type = ntohs(p->eh->ether_type);
+    p->dsize = p->eth_dsize;
+
+    if (ScIdsMode())
+    {
+        /* See if there are any ether_type only rules that match */
+        fpEvalEtherTypeOnlyRules(snort_conf->eth_type_only_lists, p);
+        p->proto_bits |= PROTO_BIT__ETH_II;
+    }
+
+    switch (p->eth_type)
     {
         case ETHERNET_TYPE_IP:
             DecodeIP(pkt + ETHERNET_HEADER_LEN, len - ETHERNET_HEADER_LEN, p);
@@ -1078,10 +1104,13 @@ void DecodeMPLS(const uint8_t* pkt, const uint32_t len, \
Packet* p)  exp = (uint8_t)(mpls_h & 0x0000000E);
         label = (mpls_h>>4) & 0x000FFFFF;
 
-        if((label<NUM_RESERVED_LABELS)&&((iRet = checkMplsHdr(label, exp, bos, ttl, \
p)) < 0)) +        if ((label < NUM_RESERVED_LABELS) &&
+            ((iRet = checkMplsHdr(label, exp, bos, ttl, p)) < 0))
+        {
             return;
+        }
 
-        if( bos )
+        if (bos)
         {
             p->mplsHdr.label = label;
             p->mplsHdr.exp = exp;
@@ -1155,7 +1184,8 @@ void DecodeEthOverMPLS(const uint8_t* pkt, const uint32_t len, \
Packet* p)  }
 
     /* lay the ethernet structure over the packet data */
-    p->eh = (EtherHdr *) pkt; // FIXTHIS squashes outer eth!
+    /* FIXME: Broken if PWMCW (RFC 4385) is in use.  Will be off by 4 bytes. */
+    p->eh = (EtherHdr *) pkt;  /* FIXME: squashes outer eth! */
     PushLayer(PROTO_ETH, p, pkt, sizeof(*p->eh));
 
     DEBUG_WRAP(
@@ -1163,8 +1193,22 @@ void DecodeEthOverMPLS(const uint8_t* pkt, const uint32_t len, \
                Packet* p)
                 *p->eh->ether_src, *p->eh->ether_dst);
             );
 
+    /* Set some convienience pointers for eth rules. */
+    /* FIXME: eth_data is broken if PWMCW (RFC 4385) is in use.  Will be off by 4 \
bytes. */ +    p->eth_data = (p->pkt + ETHERNET_HEADER_LEN);       /* FIXME: squashes \
the orig eth data. */ +    p->eth_dsize = (uint16_t)(len - ETHERNET_HEADER_LEN);
+    p->eth_type = ntohs(p->eh->ether_type);
+    p->dsize = p->eth_dsize;
+
+    if (ScIdsMode())
+    {
+        /* See if there are any ether_type only rules that match */
+        fpEvalEtherTypeOnlyRules(snort_conf->eth_type_only_lists, p);
+        p->proto_bits |= PROTO_BIT__ETH_II;
+    }
+
     /* grab out the network type */
-    switch(ntohs(p->eh->ether_type))
+    switch(p->eth_type)
     {
         case ETHERNET_TYPE_IP:
             DEBUG_WRAP(
@@ -1282,7 +1326,7 @@ void DecodeVlan(const uint8_t * pkt, const uint32_t len, Packet \
* p)  );
 
     /* check to see if we've got an encapsulated LLC layer
-     * http://www.geocities.com/billalexander/ethernet.html
+     * http://web.archive.org/web/20091027113048/http://geocities.com/BillAlexander/ethernet.html
                
      */
     if(ntohs(p->vh->vth_proto) <= ETHERNET_MAX_LEN_ENCAP)
     {
@@ -1338,7 +1382,20 @@ void DecodeVlan(const uint8_t * pkt, const uint32_t len, \
Packet * p)  
             PushLayer(PROTO_VLAN, p, pkt, sizeof(*p->vh));
 
-            switch(ntohs(p->ehllcother->proto_id))
+            /* Set some convienience pointers for eth rules. */
+            p->eth_data = (p->pkt + LEN_VLAN_LLC_OTHER);
+            p->eth_dsize = (uint16_t)(len - LEN_VLAN_LLC_OTHER);
+            p->eth_type = ntohs(p->ehllcother->proto_id);
+            p->dsize = p->eth_dsize;
+
+            if (ScIdsMode())
+            {
+                /* See if there are any ether_type only rules that match */
+                fpEvalEtherTypeOnlyRules(snort_conf->eth_type_only_lists, p);
+                p->proto_bits |= PROTO_BIT__ETH_II;
+            }
+
+            switch(p->eth_type)
             {
                 case ETHERNET_TYPE_IP:
                     DecodeIP(p->pkt + LEN_VLAN_LLC_OTHER,
@@ -1403,7 +1460,20 @@ void DecodeVlan(const uint8_t * pkt, const uint32_t len, \
Packet * p)  {
         PushLayer(PROTO_VLAN, p, pkt, sizeof(*p->vh));
 
-        switch(ntohs(p->vh->vth_proto))
+        /* Set some convienience pointers for eth rules. */
+        p->eth_data = (pkt + sizeof(VlanTagHdr));
+        p->eth_dsize = (uint16_t)(len - sizeof(VlanTagHdr));
+        p->eth_type = ntohs(p->vh->vth_proto);
+        p->dsize = p->eth_dsize;
+
+        if (ScIdsMode())
+        {
+            /* See if there are any ether_type only rules that match */
+            fpEvalEtherTypeOnlyRules(snort_conf->eth_type_only_lists, p);
+            p->proto_bits |= PROTO_BIT__ETH_II;
+        }
+
+        switch(p->eth_type)
         {
             case ETHERNET_TYPE_IP:
                 DecodeIP(pkt + sizeof(VlanTagHdr),
@@ -4900,12 +4970,25 @@ void DecodeGRE(const uint8_t *pkt, const uint32_t len, Packet \
*p)  PushLayer(PROTO_GRE, p, pkt, hlen);
     payload_len = len - hlen;
 
+    /* Set some convienience pointers for eth rules. */
+    p->eth_data = (pkt + hlen);            /* FIXME: squashes the orig eth data. */
+    p->eth_dsize = (uint16_t)payload_len;
+    p->eth_type = ntohs(p->greh->ether_type);
+    p->dsize = p->eth_dsize;
+
+    if (ScIdsMode())
+    {
+        /* See if there are any ether_type only rules that match */
+        fpEvalEtherTypeOnlyRules(snort_conf->eth_type_only_lists, p);
+        p->proto_bits |= PROTO_BIT__ETH_II;
+    }
+
     /* Send to next protocol decoder */
     /* As described in RFC 2784 the possible protocols are listed in
      * RFC 1700 under "ETHER TYPES"
      * See also "Current List of Protocol Types" in RFC 1701
      */
-    switch (GRE_PROTO(p->greh))
+    switch (p->eth_type)
     {
         case ETHERNET_TYPE_IP:
             DecodeIP(pkt + hlen, payload_len, p);
@@ -6218,7 +6301,22 @@ void DecodeIEEE80211Pkt(Packet * p, const DAQ_PktHdr_t * \
                pkthdr,
                 printf("   PROTO: 0x%04X\n", ntohs(p->ehllcother->proto_id));
 #endif
 
-                switch(ntohs(p->ehllcother->proto_id))
+				/* Set some convienience pointers for eth rules. */
+                p->eth_data = (p->pkt + IEEE802_11_DATA_HDR_LEN + sizeof(EthLlc) +
+                               sizeof(EthLlcOther));
+                p->eth_dsize = (uint16_t)(cap_len - IEEE802_11_DATA_HDR_LEN - \
sizeof(EthLlc) - +                                          sizeof(EthLlcOther));
+                p->eth_type = ntohs(p->ehllcother->proto_id);
+                p->dsize = p->eth_dsize;
+
+                if (ScIdsMode())
+                {
+                    /* See if there are any ether_type only rules that match */
+                    fpEvalEtherTypeOnlyRules(snort_conf->eth_type_only_lists, p);
+                    p->proto_bits |= PROTO_BIT__ETH_II;
+                }
+
+                switch(p->eth_type)
                 {
                     case ETHERNET_TYPE_IP:
                         DecodeIP(p->pkt + IEEE802_11_DATA_HDR_LEN + sizeof(EthLlc) +
diff --git a/src/decode.h b/src/decode.h
index 1941181..6c39e63 100644
--- a/src/decode.h
+++ b/src/decode.h
@@ -70,6 +70,15 @@
 #define ETHERNET_TYPE_MPLS_UNICAST    0x8847
 #define ETHERNET_TYPE_MPLS_MULTICAST  0x8848
 
+/*
+ * Raw Ethernet II frames don't have a direct identifier.  For use within
+ * Snort, the value 0x2ffff (chosen at random) should be out of the range
+ * of any other supported protocols and will serve to identify a raw
+ * ethernet II rule from other rules.
+ */
+#define ETH_II_FRAME                  0x2ffff
+
+
 #define ETH_DSAP_SNA                  0x08    /* SNA */
 #define ETH_SSAP_SNA                  0x00    /* SNA */
 #define ETH_DSAP_STP                  0x42    /* Spanning Tree Protocol */
@@ -632,6 +641,9 @@ struct enc_header {
 #define PKT_STREAM_ORDER_BAD 0x02000000  /* this stream had at last one gap */
 #define PKT_REASSEMBLED_OLD  0x04000000  /* for backwards compat with so rules */
 
+/* Packet is an ETH_II frame rule */
+#define PKT_ETH_II_RULE      0x08000000
+
 // 0x0F800000 are available
 
 #define PKT_PDU_FULL (PKT_PDU_HEAD | PKT_PDU_TAIL)
@@ -872,7 +884,7 @@ typedef struct _Pflog3_hdr
 #define PFLOG3_HDRMIN (PFLOG3_HDRLEN - PFLOG_PADLEN)
 
 /*
- * ssl_pkttype values.
+ * sll_pkttype values.
  */
 
 #define LINUX_SLL_HOST          0
@@ -881,7 +893,7 @@ typedef struct _Pflog3_hdr
 #define LINUX_SLL_OTHERHOST     3
 #define LINUX_SLL_OUTGOING      4
 
-/* ssl protocol values */
+/* sll protocol values */
 
 #define LINUX_SLL_P_802_3       0x0001  /* Novell 802.3 frames without 802.2 LLC \
header */  #define LINUX_SLL_P_802_2       0x0004  /* 802.2 frames (not D/I/X \
Ethernet) */ @@ -980,6 +992,7 @@ typedef struct _WifiHdr
 #define SET_IP_HLEN(iph, value)  ((iph)->ip_verhl = (unsigned char)(((iph)->ip_verhl \
& 0xf0) | (value & 0x0f)))  
 #define NUM_IP_PROTOS 256
+#define NUM_ETH_TYPES 65535
 
 /* Last updated 6/2/2010.
    Source: http://www.iana.org/assignments/protocol-numbers/protocol-numbers.xml */
@@ -1656,6 +1669,7 @@ typedef struct _Packet
     const uint8_t *ip_frag_start;
     const uint8_t *ip_options_data;
     const uint8_t *tcp_options_data;
+    const uint8_t *eth_data;       /* ETH_II Frame payload pointer */
     //^^^-----------------------------
 
     void *ssnptr;               /* for tcp session tracking info... */
@@ -1704,6 +1718,8 @@ typedef struct _Packet
     uint16_t alt_dsize;         /* the dsize of a packet before munging (used for \
                log)*/
     uint16_t actual_ip_len;     /* for logging truncated pkts (usually by small \
snaplen)*/  uint16_t outer_ip_dsize;    /* Outer IP payload size */
+    uint16_t eth_dsize;         /* ETH_II frame payload size */
+    uint16_t eth_type;          /* ETH_II Type.  decode.c stores here so other \
things can find it. */  //^^^-----------------------------
 
     uint16_t frag_offset;       /* fragment offset number */
@@ -1801,6 +1817,7 @@ typedef struct _Packet
 #define PROTO_BIT__ICMP     0x0010
 #define PROTO_BIT__TEREDO   0x0020
 #define PROTO_BIT__GTP      0x0040
+#define PROTO_BIT__ETH_II   0x0080
 #define PROTO_BIT__ALL      0xffff
 
 #define IsIP(p) (IPH_IS_VALID(p))
@@ -1819,8 +1836,10 @@ typedef struct _Packet
 #define BIT(i) (0x1 << (i-1))
 
 #ifdef SUP_IP6
-/* Sets the callbacks to point at the family selected by
- *  * "family".  "family" is either AF_INET or AF_INET6 */
+/*
+ * Sets the callbacks to point at the family selected by
+ * "family".  "family" is either AF_INET or AF_INET6
+ */
 #define CALLBACK_IP 0
 #define CALLBACK_ICMP_ORIG 1
 
diff --git a/src/detect.c b/src/detect.c
index c4d9185..d83d38c 100644
--- a/src/detect.c
+++ b/src/detect.c
@@ -494,38 +494,38 @@ int Detect(Packet * p)
     int detected = 0;
     PROFILE_VARS;
 
-    if ((p == NULL) || !IPH_IS_VALID(p))
-    {
+    if (!p)
         return 0;
-    }
-
 
-    if (!snort_conf->ip_proto_array[GET_IPH_PROTO(p)])
+    if (IPH_IS_VALID(p))
     {
+        if (!snort_conf->ip_proto_array[GET_IPH_PROTO(p)])
+        {
 #ifdef GRE
 # ifdef SUP_IP6
-        switch (p->outer_family)
-        {
-            case AF_INET:
-                if (!snort_conf->ip_proto_array[p->outer_ip4h.ip_proto])
-                    return 0;
-                break;
+            switch (p->outer_family)
+            {
+                case AF_INET:
+                    if (!snort_conf->ip_proto_array[p->outer_ip4h.ip_proto])
+                        return 0;
+                    break;
 
-            case AF_INET6:
-                if (!snort_conf->ip_proto_array[p->outer_ip6h.next])
-                    return 0;
-                break;
+                case AF_INET6:
+                    if (!snort_conf->ip_proto_array[p->outer_ip6h.next])
+                        return 0;
+                    break;
 
-            default:
-                return 0;
-        }
+                default:
+                    return 0;
+            }
 # else
-        if ((p->outer_iph == NULL) || \
                !snort_conf->ip_proto_array[p->outer_iph->ip_proto])
-            return 0;
+            if ((p->outer_iph == NULL) || \
!snort_conf->ip_proto_array[p->outer_iph->ip_proto]) +                return 0;
 # endif  /* SUP_IP6 */
 #else
-        return 0;
+            return 0;
 #endif  /* GRE */
+        }
     }
 
     if (p->packet_flags & PKT_PASS_RULE)
diff --git a/src/detection-plugins/Makefile.am b/src/detection-plugins/Makefile.am
index af40c8e..0618383 100644
--- a/src/detection-plugins/Makefile.am
+++ b/src/detection-plugins/Makefile.am
@@ -61,7 +61,8 @@ sp_urilen_check.c sp_urilen_check.h \
 sp_file_data.c sp_file_data.h \
 sp_base64_decode.c sp_base64_decode.h \
 sp_base64_data.c sp_base64_data.h \
-sp_pkt_data.c sp_pkt_data.h
+sp_pkt_data.c sp_pkt_data.h \
+sp_ether_type.c sp_ether_type.h
 
 copy_files = \
 	if test -f $$dst_file; then \
diff --git a/src/detection-plugins/Makefile.in b/src/detection-plugins/Makefile.in
index 593397c..2a7f2ee 100644
--- a/src/detection-plugins/Makefile.in
+++ b/src/detection-plugins/Makefile.in
@@ -72,7 +72,8 @@ am__libspd_a_SOURCES_DIST = detection_options.c detection_options.h \
\  sp_tcp_win_check.h sp_ttl_check.c sp_ttl_check.h \
 	sp_urilen_check.c sp_urilen_check.h sp_file_data.c \
 	sp_file_data.h sp_base64_decode.c sp_base64_decode.h \
-	sp_base64_data.c sp_base64_data.h sp_pkt_data.c sp_pkt_data.h
+	sp_base64_data.c sp_base64_data.h sp_pkt_data.c sp_pkt_data.h \
+    sp_ether_type.c sp_ether_type.h
 @BUILD_REACT_TRUE@am__objects_1 = sp_react.$(OBJEXT)
 @BUILD_RESPOND3_TRUE@am__objects_2 = sp_respond3.$(OBJEXT)
 am_libspd_a_OBJECTS = detection_options.$(OBJEXT) sp_asn1.$(OBJEXT) \
@@ -94,7 +95,7 @@ am_libspd_a_OBJECTS = detection_options.$(OBJEXT) sp_asn1.$(OBJEXT) \
\  sp_tcp_win_check.$(OBJEXT) sp_ttl_check.$(OBJEXT) \
 	sp_urilen_check.$(OBJEXT) sp_file_data.$(OBJEXT) \
 	sp_base64_decode.$(OBJEXT) sp_base64_data.$(OBJEXT) \
-	sp_pkt_data.$(OBJEXT)
+	sp_pkt_data.$(OBJEXT) sp_ether_type.$(OBJEXT)
 nodist_libspd_a_OBJECTS = sf_snort_plugin_hdropts.$(OBJEXT)
 libspd_a_OBJECTS = $(am_libspd_a_OBJECTS) $(nodist_libspd_a_OBJECTS)
 DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
@@ -301,7 +302,8 @@ sp_urilen_check.c sp_urilen_check.h \
 sp_file_data.c sp_file_data.h \
 sp_base64_decode.c sp_base64_decode.h \
 sp_base64_data.c sp_base64_data.h \
-sp_pkt_data.c sp_pkt_data.h
+sp_pkt_data.c sp_pkt_data.h \
+sp_ether_type.c sp_ether_type.h
 
 copy_files = \
 	if test -f $$dst_file; then \
diff --git a/src/detection-plugins/detection_options.c \
b/src/detection-plugins/detection_options.c index 8bf95ea..aedfaea 100644
--- a/src/detection-plugins/detection_options.c
+++ b/src/detection-plugins/detection_options.c
@@ -69,6 +69,7 @@
 #include "sp_isdataat.h"
 #include "sp_pattern_match.h"
 #include "sp_pcre.h"
+#include "sp_ether_type.h"
 #ifdef ENABLE_REACT
 #include "sp_react.h"
 #endif
@@ -225,6 +226,9 @@ uint32_t detection_option_hash_func(SFHASHFCN *p, unsigned char \
*k, int n)  case RULE_OPTION_TYPE_URILEN:
             hash = UriLenCheckHash(key->option_data);
             break;
+        case RULE_OPTION_TYPE_ETHER_TYPE:
+            hash = EtherTypeHash(key->option_data);
+            break;
 #ifdef DYNAMIC_PLUGIN
         case RULE_OPTION_TYPE_HDR_OPT_CHECK:
             hash = HdrOptCheckHash(key->option_data);
@@ -379,6 +383,9 @@ int detection_option_key_compare_func(const void *k1, const void \
*k2, size_t n)  case RULE_OPTION_TYPE_URILEN:
             ret = UriLenCheckCompare(key1->option_data, key2->option_data);
             break;
+        case RULE_OPTION_TYPE_ETHER_TYPE:
+            ret = EtherTypeCompare(key1->option_data, key2->option_data);
+            break;
 #ifdef DYNAMIC_PLUGIN
         case RULE_OPTION_TYPE_HDR_OPT_CHECK:
             ret = HdrOptCheckCompare(key1->option_data, key2->option_data);
@@ -516,6 +523,9 @@ int detection_hash_free_func(void *option_key, void *data)
         case RULE_OPTION_TYPE_URILEN:
             free(key->option_data);
             break;
+        case RULE_OPTION_TYPE_ETHER_TYPE:
+            free(key->option_data);
+            break;
 #ifdef DYNAMIC_PLUGIN
         case RULE_OPTION_TYPE_HDR_OPT_CHECK:
             break;
@@ -771,7 +781,8 @@ char *option_type_str[] =
     "RULE_OPTION_TYPE_TCP_SEQ",
     "RULE_OPTION_TYPE_TCP_WIN",
     "RULE_OPTION_TYPE_TTL",
-    "RULE_OPTION_TYPE_URILEN"
+    "RULE_OPTION_TYPE_URILEN",
+    "RULE_OPTION_TYPE_ETHER_TYPE"
 #ifdef DYNAMIC_PLUGIN
     ,
     "RULE_OPTION_TYPE_HDR_OPT_CHECK",
@@ -1138,6 +1149,7 @@ int detection_option_node_evaluate(detection_option_tree_node_t \
*node, detection  case RULE_OPTION_TYPE_TCP_WIN:
             case RULE_OPTION_TYPE_TTL:
             case RULE_OPTION_TYPE_URILEN:
+            case RULE_OPTION_TYPE_ETHER_TYPE:
 #ifdef DYNAMIC_PLUGIN
             case RULE_OPTION_TYPE_HDR_OPT_CHECK:
             case RULE_OPTION_TYPE_PREPROCESSOR:
diff --git a/src/detection-plugins/sp_ether_type.c \
b/src/detection-plugins/sp_ether_type.c new file mode 100644
index 0000000..926864c
--- /dev/null
+++ b/src/detection-plugins/sp_ether_type.c
@@ -0,0 +1,361 @@
+/*
+** Copyright (C) 2011 Joshua Kinard <kumba@gentoo.org>
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License Version 2 as
+** published by the Free Software Foundation.  You may not use, modify or
+** distribute this program under any other version of the GNU General
+** Public License.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program; if not, write to the Free Software
+** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+/* $Id$ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/types.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+#include "sf_types.h"
+#include "rules.h"
+#include "treenodes.h"
+#include "decode.h"
+#include "plugbase.h"
+#include "parser.h"
+#include "util.h"
+#include "snort_debug.h"
+#include "plugin_enum.h"
+#include "sp_ether_type.h"
+
+#include "snort.h"
+#include "profiler.h"
+#ifdef PERF_PROFILING
+PreprocStats etherTypePerfStats;
+extern PreprocStats ruleOTNEvalPerfStats;
+#endif
+
+#include "sfhashfcn.h"
+#include "detection_options.h"
+
+
+/**
+ * EtherTypeHash - Hash function for ether_type.
+ * @data: pointer to EtherTypeData.
+ *
+ * Returns a uint32_t representing the hash.
+ */
+uint32_t EtherTypeHash(void *data)
+{
+    uint32_t a, b, c;
+    EtherTypeData *etd = (EtherTypeData *)data;
+
+    a = etd->value;
+    b = etd->operator;
+    c = RULE_OPTION_TYPE_ETHER_TYPE;
+    final(a, b, c);
+
+    return c;
+}
+
+/**
+ * EtherTypeCompare - Comparator function for ether_type.
+ * @l: pointer to EtherTypeData (left side).
+ * @r: pointer to EtherTypeData (right side).
+ *
+ * Returns the comparison result of the two data structures.
+ */
+int EtherTypeCompare(void *l, void *r)
+{
+    EtherTypeData *left = (EtherTypeData *)l;
+    EtherTypeData *right = (EtherTypeData *)r;
+
+    if (!left)
+        return (!right ? DETECTION_OPTION_EQUAL : 
+                         DETECTION_OPTION_NOT_EQUAL);
+    
+    if (!right)
+        return (!left ? DETECTION_OPTION_EQUAL : 
+                        DETECTION_OPTION_NOT_EQUAL);
+
+    if (left->value == right->value)
+        return DETECTION_OPTION_NOT_EQUAL;
+
+    if (left->operator == right->operator)
+        return DETECTION_OPTION_NOT_EQUAL;
+
+    return DETECTION_OPTION_EQUAL;
+}
+
+/**
+ * EtherTypeSetup - Setup function for ether_type.
+ *
+ * Links the 'ether_type' keyword to its initialization function.
+ * Returns void.
+ */
+void EtherTypeSetup(void)
+{
+    /* Map the keyword to an initialization/processing function */
+    RegisterRuleOption("ether_type", EtherTypeInit, NULL, OPT_TYPE_DETECTION, NULL);
+    
+#ifdef PERF_PROFILING
+    RegisterPreprocessorProfile("ether_type", &etherTypePerfStats, 3, \
&ruleOTNEvalPerfStats); +#endif
+
+    DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN,"Plugin: EtherType Initialized\n"););
+}
+
+/**
+ * EtherTypeInit - Initialization function for ether_type.
+ * @data: pointer to EtherTypeData (as char *).
+ * @otn: pointer to OptTreeNode structure.
+ * @protocol: integer value representing the transport-layer protocol.
+ *
+ * Attaches the rule option data to the appropriate data structure and links
+ * in the evaluator function to the function pointer list.  Returns void.
+ */
+void EtherTypeInit(char *data, OptTreeNode *otn, int protocol)
+{
+    OptFpList *fpl;
+    EtherTypeData *etd;
+    void *etd_dup;
+
+    /* Rule must be an 'eth' rule to use this rule option */
+    if (protocol != ETH_II_FRAME)
+        FatalError("Error at %s:%d: 'ether_type' can only be used with "
+                   "an 'eth' rule.\n", file_name, file_line);
+
+    /* Allocate the data structure. */
+    etd = (EtherTypeData *)SnortAlloc(sizeof(EtherTypeData));
+
+    /* Parse the keyword's parameters and configure the data structure. */
+    EtherTypeParse(data, etd);
+
+    /* Check for a duplicate entry in the otn. */
+    if (add_detection_option(RULE_OPTION_TYPE_ETHER_TYPE,
+                             (void *)etd, &etd_dup) == DETECTION_OPTION_EQUAL)
+    {
+        free(etd);
+        etd = (EtherTypeData *)etd_dup;
+    }
+
+    /*
+     *  Set the ds_list for the first ether_type check for a rule.  This
+     *  is needed for the high-speed rule optimization.
+     */
+    if (!otn->ds_list[PLUGIN_ETHER_TYPE])
+        otn->ds_list[PLUGIN_ETHER_TYPE] = etd;
+
+    /*
+     * Finally, attach the option's detection function to the rule's detection
+     * function pointer list
+     */
+    fpl = AddOptFuncToList(EtherTypeEval, otn);
+    fpl->type = RULE_OPTION_TYPE_ETHER_TYPE;
+    fpl->context = (void *)etd;
+}
+
+/**
+ * EtherTypeParse - Parsing function for ether_type.
+ * @data: pointer to EtherTypeData (as char *).
+ * @otn: pointer to OptTreeNode structure.
+ *
+ * Parses the rule option's parameter list and fills in the EtherTypeData
+ * structure.  Returns void.
+ */
+void EtherTypeParse(char *data, EtherTypeData *etd)
+{
+    uint32_t etype;
+
+    if (!etd || !data)
+        FatalError("Error at %s:%d: Unable to parse the 'ether_type' "
+                   "parameters.\n", file_name, file_line);
+
+    /* Skip any leading whitespace. */
+    while(isspace((int)*data)) data++;
+
+    /* Parse the parameter string. */
+    if (*data == '!')
+    {
+        etd->operator = ETHER_TYPE_NOT_EQUAL;
+        data++;
+    }
+    else if (*data == '>')
+    {
+        etd->operator = ETHER_TYPE_GT;
+        data++;
+    }
+    else if (*data == '<')
+    {
+        etd->operator = ETHER_TYPE_LT;
+        data++;
+    }
+    else
+    {
+        etd->operator = ETHER_TYPE_EQUAL;
+    }
+
+    /* Check to see if the parameter is numeric or a string. */
+    if(isdigit((int)*data))
+    {
+        char *endptr;
+        
+        etype = strtoul(data, &endptr, 0);
+
+        if (*endptr || etype < ETHER_TYPE_MIN_VALUE || etype > UINT16_MAX)
+            FatalError("Error at %s:%d: The value passed to 'ether_type' "
+                       "is invalid or out of range.\n", file_name, file_line);
+    }
+    else
+    {
+        /* Lookup the string name and get its corresponding value. */
+        etype = etype_lookup(data);
+
+        if (etype == ETHER_TYPE_LOOKUP_ERROR)
+            FatalError("Error at %s:%d: The name passed to 'ether_type' "
+                       "is invalid.\n", file_name, file_line);
+    }
+    etd->value = (uint16_t)etype;
+
+    return;
+}
+
+/**
+ * EtherTypeEval - Evaluation function for ether_type.
+ * @data: pointer to EtherTypeData (as char *).
+ * @p: pointer to Packet structure.
+ *
+ * Evaluates the rule option against the packet pointed to by 'p'.  Returns
+ * either DETECTION_OPTION_MATCH or DETECTION_OPTION_NO_MATCH.
+ */
+int EtherTypeEval(void *data, Packet *p)
+{
+    EtherTypeData *etd = (EtherTypeData *)data;
+    int rval = DETECTION_OPTION_NO_MATCH;
+    PROFILE_VARS;
+
+    if(!p->eh || !etd)
+        return rval;
+
+    PREPROC_PROFILE_START(etherTypePerfStats);
+
+    switch (etd->operator)
+    {
+        case ETHER_TYPE_EQUAL:
+            if (etd->value == p->eth_type)
+                rval = DETECTION_OPTION_MATCH;
+            break;
+
+        case ETHER_TYPE_NOT_EQUAL:
+            if (etd->value != p->eth_type)
+                rval = DETECTION_OPTION_MATCH;
+            break;
+
+        case ETHER_TYPE_LT:
+            if (etd->value < p->eth_type)
+                rval = DETECTION_OPTION_MATCH;
+            break;
+
+        case ETHER_TYPE_GT:
+            if (etd->value > p->eth_type)
+                rval = DETECTION_OPTION_MATCH;
+            break;
+
+        default:
+            break;
+    }
+
+    PREPROC_PROFILE_END(etherTypePerfStats);
+
+    return rval;
+}
+
+
+
+/* Helper functions used by other areas of Snort. */
+
+/**
+ * GetEthTypes - creates a map of ethernet types set in a rule.
+ * @data: pointer to EtherTypeData (as char *).
+ * @etype_array: pointer to array of ethernet type mappings.
+ * @eta_size: size of the array pointed at by etype_array.
+ */
+int GetEthTypes(void *data, uint8_t *etype_array, int eta_size)
+{
+    EtherTypeData *etd = (EtherTypeData *)data;
+    int i;
+
+    if (!etype_array || (eta_size < NUM_ETH_TYPES))
+        return -1;
+
+    /* Eth type not set, so include them all. */
+    if (!data)
+    {
+        memset(etype_array, 1, eta_size);
+        return 0;
+    }
+
+    memset(etype_array, 0, eta_size);
+
+    switch (etd->operator)
+    {
+        case ETHER_TYPE_EQUAL:
+            etype_array[etd->value] = 1;
+            break;
+
+        case ETHER_TYPE_NOT_EQUAL:
+            for (i = 0; i < etd->value; i++)
+                etype_array[i] = 1;
+            for (i += 1; i < NUM_ETH_TYPES; i++)
+                etype_array[i] = 1;
+            break;
+
+        case ETHER_TYPE_LT:
+            for (i = 0; i < etd->value; i++)
+                etype_array[i] = 1;
+            break;
+
+        case ETHER_TYPE_GT:
+            for (i = (etd->value + 1); i < NUM_ETH_TYPES; i++)
+                etype_array[i] = 1;
+            break;
+
+        default:
+            return -1;
+    }
+
+    return 0;
+}
+
+#if 0
+/**
+ * GetOtnEthType - extract the ether_type field from an otn.
+ * @otn: pointer to OptTreeNode.
+ *
+ * Not used at present.  Mimiced from ip_proto, so maybe one day?
+ */
+int GetOtnEthType(OptTreeNode *otn)
+{
+   EtherTypeData *etd;
+
+   if (!otn)
+       return -1;
+
+   etd = (EtherTypeData *)otn->ds_list[PLUGIN_ETHER_TYPE];
+
+   if (etd && (etd->operator == ETHER_TYPE_EQUAL))
+       return (int)etd->value;
+
+   return -1;
+}
+#endif
diff --git a/src/detection-plugins/sp_ether_type.h \
b/src/detection-plugins/sp_ether_type.h new file mode 100644
index 0000000..5a16280
--- /dev/null
+++ b/src/detection-plugins/sp_ether_type.h
@@ -0,0 +1,125 @@
+/*
+** Copyright (C) 2011 Joshua Kinard <kumba@gentoo.org>
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License Version 2 as
+** published by the Free Software Foundation.  You may not use, modify or
+** distribute this program under any other version of the GNU General
+** Public License.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program; if not, write to the Free Software
+** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+/* $Id$ */
+#ifndef __SP_ETHER_TYPE_H__
+#define __SP_ETHER_TYPE_H__
+
+/* Operator definitions for sctp_payload_id. */
+#define ETHER_TYPE_EQUAL               0x01
+#define ETHER_TYPE_NOT_EQUAL           0x02
+#define ETHER_TYPE_LT                  0x03
+#define ETHER_TYPE_GT                  0x04
+
+/* The error value if an ethertype lookup fails. */
+#define ETHER_TYPE_LOOKUP_ERROR        0xdeadbac9
+
+/* Smallest numeric ethertype that we will accept. */
+#define ETHER_TYPE_MIN_VALUE           0x0600
+
+
+/* EtherType data structure. */
+typedef struct _EtherTypeData
+{
+    uint16_t value;
+    uint8_t operator;
+} EtherTypeData;
+
+
+/**
+ * struct _ethertype_map_t.
+ * @name: char pointer for the etherype name.
+ * @etype: uint16_t ethertype value.
+ */
+typedef struct _ethertype_map_t {
+        const char *name;
+        const uint32_t etype;
+} ethertype_map_t;
+
+
+/*
+ * Mapping of Ethertype name -> value.
+ *
+ * This is a short list.  It should encompass the most
+ * common ethernet frame types that one might ever see
+ * on a network.
+ */
+static const ethertype_map_t etype_table[] =
+{
+    {"xerox", 0x0600},      /* Xerox NS IDP */
+    {"ipv4", 0x0800},       /* IP version 4 */
+    {"x75", 0x0801},        /* X.75 Internet */
+    {"nbs", 0x0802},        /* NBS Internet */
+    {"ecma", 0x0803},       /* ECMA Internet */
+    {"chaos", 0x0804},      /* CHAOSNet */
+    {"x25", 0x0805},        /* X.25 Level 3 */
+    {"arp", 0x0806},        /* Address Resolution Protocol */
+    {"rarp", 0x0835},       /* Reverse ARP */
+    {"wol", 0x0842},        /* Wake On LAN */
+    {"ax25", 0x08ff},       /* AX.25 over Ethernet (G8BPQ) */
+    {"decnet", 0x6003},     /* DECnet DNA */
+    {"apple", 0x809b},      /* Appletalk */
+    {"aarp", 0x80f3},       /* Appletalk ARP */
+    {"vlan", 0x8100},       /* VLAN Tagged 802.1q */
+    {"netbeui", 0x8191},    /* NetBEUI */
+    {"ipx", 0x8137},        /* Novell IPX/SPX */
+    {"snmp", 0x814c},       /* SNMP over Ethernet */
+    {"ipv6", 0x86dd},       /* IP version 6 */
+    {"slow", 0x8809},       /* Slow Protocols */
+    {"ppp", 0x880b},        /* Point-to-Point Protocol */
+    {"mpls", 0x8847},       /* MPLS Unicast */
+    {"pppoed", 0x8863},     /* PPP over Ethernet Discovery */
+    {"pppoes", 0x8864},     /* PPP over Ethernet Session */
+    {"eapol", 0x888e},      /* EAPOL (EAP over LAN), IEEE 802.1x */
+    {"aoe", 0x88a2},        /* ATA over Ethernet */
+    {"lldp", 0x88cc},       /* Logical Link Discovery Protocol */
+    {"fcoe", 0x8906},       /* FibreChannel over Ethernet */
+    {"fip", 0x8914},        /* FCoE Initialization Protocol */
+    {"tte", 0x891d},        /* TTEthernet */
+    {"loop", 0x9000},       /* Loopback */
+};
+
+
+/**
+ * etype_lookup - ethertype lookup function.
+ * @name: ethertype name to look up in etype_table.
+ */
+static const inline uint32_t etype_lookup(const char *name)
+{
+        const ethertype_map_t *e = etype_table;
+
+        for (; e->name != NULL; ++e)
+                if (strcmp(e->name, name) == 0)
+                        return e->etype;
+
+        return ETHER_TYPE_LOOKUP_ERROR;
+}
+
+
+/* Prototypes. */
+uint32_t EtherTypeHash(void *data);
+int EtherTypeCompare(void *l, void *r);
+void EtherTypeSetup(void);
+void EtherTypeInit(char *data, OptTreeNode *otn, int protocol);
+void EtherTypeParse(char *data, EtherTypeData *etd);
+int EtherTypeEval(void *data, Packet *p);
+int GetEthTypes(void *data, uint8_t *etype_array, int eta_size);
+int GetOtnEthType(OptTreeNode *otn);
+
+#endif  /* __SP_ETHER_TYPE_H__ */
diff --git a/src/dynamic-plugins/sf_engine/sf_snort_packet.h \
b/src/dynamic-plugins/sf_engine/sf_snort_packet.h index 1541af9..bcdeab9 100644
--- a/src/dynamic-plugins/sf_engine/sf_snort_packet.h
+++ b/src/dynamic-plugins/sf_engine/sf_snort_packet.h
@@ -530,6 +530,7 @@ typedef struct _SFSnortPacket
     const uint8_t *ip_frag_start;
     const uint8_t *ip4_options_data;
     const uint8_t *tcp_options_data;
+    const uint8_t *ethernet_data;
 
     void *stream_session_ptr;
     void *fragmentation_tracking_ptr;
@@ -573,6 +574,8 @@ typedef struct _SFSnortPacket
     uint16_t normalized_payload_size;
     uint16_t actual_ip_length;
     uint16_t outer_ip_payload_size;
+    uint16_t eth_payload_size;
+    uint16_t eth_type;
 
     uint16_t ip_fragment_offset;
     uint16_t ip_frag_length;
diff --git a/src/fpcreate.c b/src/fpcreate.c
index f19a8c2..6e57d85 100644
--- a/src/fpcreate.c
+++ b/src/fpcreate.c
@@ -50,6 +50,7 @@
 #include "sp_icmp_type_check.h"
 #include "sp_file_data.h"
 #include "sp_ip_proto.h"
+#include "sp_ether_type.h"
 #include "plugin_enum.h"
 #include "util.h"
 #include "rules.h"
@@ -88,6 +89,8 @@ enum
 
 static void fpAddIpProtoOnlyRule(SF_LIST **, OptTreeNode *);
 static void fpRegIpProto(uint8_t *, OptTreeNode *);
+static void fpAddRawEthIIRule(SF_LIST **, OptTreeNode *);
+static void fpRegEthType(uint8_t *, OptTreeNode *otn);
 static int fpCreatePortGroups(SnortConfig *, rule_port_tables_t *);
 static void fpDeletePortGroup(void *);
 static void fpDeletePMX(void *data);
@@ -392,49 +395,49 @@ static int ServiceMapAddOtn(srmm_table_t *srmm, int proto, char \
*servicename, Op  SFGHASH * to_srv; /* to srv service rule map */
     SFGHASH * to_cli; /* to cli service rule map */
 
-    if( !servicename )
+    if (!servicename || !otn)
         return 0;
 
-    if(!otn )
-        return 0;
-
-    if( proto == IPPROTO_TCP)
-    {
-        to_srv = srmm->tcp_to_srv;
-        to_cli = srmm->tcp_to_cli;
-    }
-    else if( proto == IPPROTO_UDP)
-    {
-        to_srv = srmm->udp_to_srv;
-        to_cli = srmm->udp_to_cli;
-    }
-    else if( proto == IPPROTO_ICMP )
-    {
-        to_srv = srmm->icmp_to_srv;
-        to_cli = srmm->icmp_to_cli;
-    }
-    else if( proto ==  ETHERNET_TYPE_IP )
+    switch (proto)
     {
-        to_srv = srmm->tcp_to_srv;
-        to_cli = srmm->ip_to_cli;
-    }
-    else
-    {
-        return 0;
-    }
+        case IPPROTO_TCP:
+            to_srv = srmm->tcp_to_srv;
+            to_cli = srmm->tcp_to_cli;
+            break;
 
-    if( fpOtnFlowToServer(otn) )
-    {
-        ServiceMapAddOtnRaw( to_srv, servicename, otn );
-    }
-    else if( fpOtnFlowToClient(otn) )
-    {
-        ServiceMapAddOtnRaw( to_cli, servicename, otn );
+        case IPPROTO_UDP:
+            to_srv = srmm->udp_to_srv;
+            to_cli = srmm->udp_to_cli;
+            break;
+
+        case IPPROTO_ICMP:
+            to_srv = srmm->icmp_to_srv;
+            to_cli = srmm->icmp_to_cli;
+            break;
+
+        case ETHERNET_TYPE_IP:
+            to_srv = srmm->ip_to_srv;
+            to_cli = srmm->ip_to_cli;
+            break;
+
+        case ETH_II_FRAME:
+            to_srv = srmm->eth_to_srv;
+            to_cli = srmm->eth_to_cli;
+            break;
+
+        default:
+            return 0;
+            break;
     }
+
+    if (fpOtnFlowToServer(otn))
+        ServiceMapAddOtnRaw(to_srv, servicename, otn);
+    else if (fpOtnFlowToClient(otn))
+        ServiceMapAddOtnRaw(to_cli, servicename, otn);
     else /* else add to both sides */
     {
-        ServiceMapAddOtnRaw( to_srv, servicename, otn );
-        ServiceMapAddOtnRaw( to_cli, servicename, otn );
+        ServiceMapAddOtnRaw(to_srv, servicename, otn);
+        ServiceMapAddOtnRaw(to_cli, servicename, otn);
     }
 
     return 0;
@@ -455,6 +458,12 @@ int prmFindRuleGroupIp(PORT_RULE_MAP *prm, int ip_proto, \
PORT_GROUP **ip_group,  return prmFindRuleGroup( prm, ip_proto, -1, &src, ip_group, \
gen);  }
 
+int prmFindRuleGroupEth(PORT_RULE_MAP *prm, int eth_type, PORT_GROUP **eth_group, \
PORT_GROUP ** gen) +{
+    PORT_GROUP *src;
+    return prmFindRuleGroup( prm, eth_type, -1, &src, eth_group, gen);
+}
+
 int prmFindRuleGroupIcmp(PORT_RULE_MAP *prm, int type, PORT_GROUP **type_group, \
PORT_GROUP ** gen)  {
     PORT_GROUP *src;
@@ -2060,6 +2069,13 @@ static int fpCreateRuleMaps(SnortConfig *sc, \
                rule_port_tables_t *p)
     if (fpCreateInitRuleMap(sc->prmIcmpRTNX, p->icmp_src, p->icmp_dst, \
p->icmp_anyany, p->icmp_nocontent))  return -1;
 
+    sc->prmEthRTNX = prmNewMap();
+    if (sc->prmEthRTNX == NULL)
+        return 1;
+
+    if (fpCreateInitRuleMap(sc->prmEthRTNX, p->eth_src, p->eth_dst, p->eth_anyany, \
p->eth_nocontent)) +        return -1;
+
     return 0;
 }
 
@@ -2091,6 +2107,12 @@ static void fpFreeRuleMaps(SnortConfig *sc)
         free(sc->prmIcmpRTNX);
         sc->prmIcmpRTNX = NULL;
     }
+
+    if (sc->prmEthRTNX != NULL)
+    {
+        free(sc->prmEthRTNX);
+        sc->prmEthRTNX = NULL;
+    }
 }
 
 static int fpGetFinalPattern(FastPatternConfig *fp, PatternMatchData *pmd,
@@ -2099,11 +2121,8 @@ static int fpGetFinalPattern(FastPatternConfig *fp, \
PatternMatchData *pmd,  char *pattern;
     int bytes;
 
-    if ((fp == NULL) || (pmd == NULL)
-            || (ret_pattern == NULL) || (ret_bytes == NULL))
-    {
+    if ((!fp) || (!pmd) || (!ret_pattern) || (!ret_bytes))
         return -1;
-    }
 
     pattern = pmd->pattern_buf;
     bytes = pmd->pattern_size;
@@ -2427,6 +2446,22 @@ static int fpCreatePortObject2PortGroup(SnortConfig *sc, \
PortObject2 *po, PortOb  
                 fpRegIpProto(sc->ip_proto_array, otn);
             }
+            else if (otn->proto == ETH_II_FRAME)
+            {
+                /*
+                 * If there is only one detection option and it is
+                 * ether_type, then it will be evaluated at decode
+                 * time instead of detection time.
+                 */
+                if (otn->ds_list[PLUGIN_ETHER_TYPE] &&
+                     (otn->num_detection_opts == 1))
+                {
+                    fpAddRawEthIIRule(sc->eth_type_only_lists, otn);
+                    continue;
+                }
+
+                fpRegEthType(sc->eth_type_array, otn);
+            }
 
             if (fpAddPortGroupRule(pg, otn, fp) != 0)
                 continue;
@@ -2676,6 +2711,45 @@ static int fpCreatePortGroups(SnortConfig *sc, \
                rule_port_tables_t *p)
     //LogMessage("fpcreate: calling PortObjectFree2(po2), line = %d\n",__LINE__ );
     PortObject2Free(po2);
 
+    /* ETH */
+    po2 = PortObject2Dup(p->eth_anyany);
+    if (po2 == NULL)
+        FatalError("Could not create a PortObject version 2 for eth-any-any \
rules\n!"); +
+    if (!fpDetectSplitAnyAny(fp))
+        add_any_any = po2;
+
+    if (fpDetectGetDebugPrintRuleGroupBuildDetails(fp))
+        LogMessage("\nETH-SRC ");
+
+    if (fpCreatePortTablePortGroups(sc, p->eth_src, add_any_any))
+    {
+        LogMessage("fpCreatePorTablePortGroups failed-eth_src\n");
+        return -1;
+    }
+
+    if (fpDetectGetDebugPrintRuleGroupBuildDetails(fp))
+        LogMessage("\nETH-DST ");
+
+    if (fpCreatePortTablePortGroups(sc, p->eth_dst, add_any_any))
+    {
+        LogMessage("fpCreatePorTablePortGroups failed-eth_dst\n");
+        return -1;
+    }
+
+    if (fpDetectGetDebugPrintRuleGroupBuildDetails(fp))
+        LogMessage("\nETH-ANYANY ");
+
+    if (fpCreatePortObject2PortGroup(sc, po2, 0))
+    {
+        LogMessage("fpCreatePorTablePortGroups failed-eth any-any\n");
+        return -1;
+    }
+
+    p->eth_anyany->data = po2->data;
+    p->eth_anyany->data_free = fpDeletePortGroup;
+    po2->data = 0;
+    PortObject2Free(po2);
     return 0;
 }
 
@@ -2716,7 +2790,8 @@ void fpWalkOtns(int enabled, OtnWalkFcn fcn)
                 continue;
 
             if ((rtn->proto == IPPROTO_TCP) || (rtn->proto == IPPROTO_UDP)
-                || (rtn->proto == IPPROTO_ICMP) || (rtn->proto == ETHERNET_TYPE_IP))
+                || (rtn->proto == IPPROTO_ICMP) || (rtn->proto == ETHERNET_TYPE_IP)
+                || (rtn->proto == ETH_II_FRAME))
             {
                 //do operation
                 if ( enabled && (otn->rule_state != RULE_STATE_ENABLED) )
@@ -2753,7 +2828,8 @@ static int fpCreateServiceMaps(SnortConfig *sc)
             rtn = getRtnFromOtn(otn, policyId);
 
             if (rtn && ((rtn->proto == IPPROTO_TCP) || (rtn->proto == IPPROTO_UDP)
-                    || (rtn->proto == IPPROTO_ICMP) || (rtn->proto == \
ETHERNET_TYPE_IP))) +                    || (rtn->proto == IPPROTO_ICMP) || \
(rtn->proto == ETHERNET_TYPE_IP) +                    || (rtn->proto == \
ETH_II_FRAME)))  {
                 //do operation
 
@@ -2820,6 +2896,22 @@ void fpBuildServicePortGroupByServiceOtnList(SFGHASH *p, char \
*srvc, SF_LIST *li  continue;
             }
         }
+        else if (otn->proto == ETH_II_FRAME)
+        {
+                /*
+                 * If there is only one detection option and it is
+                 * ether_type, then it will be evaluated at decode
+                 * time instead of detection time.
+                 *
+                 * These will have already been added when adding
+                 * port groups
+                 */
+            if (otn->ds_list[PLUGIN_ETHER_TYPE] &&
+                (otn->num_detection_opts == 1))
+            {
+                continue;
+            }
+        }
 
         if (fpAddPortGroupRule(pg, otn, fp) != 0)
             continue;
@@ -2940,6 +3032,11 @@ static void fpCreateServiceMapPortGroups(SnortConfig *sc)
                              sc->srmmTable->ip_to_srv, fp);
     fpBuildServicePortGroups(sc->spgmmTable->ip_to_cli, sc->sopgTable->ip_to_srv,
                              sc->srmmTable->ip_to_cli, fp);
+
+    fpBuildServicePortGroups(sc->spgmmTable->eth_to_srv, sc->sopgTable->eth_to_srv,
+                             sc->srmmTable->eth_to_srv, fp);
+    fpBuildServicePortGroups(sc->spgmmTable->eth_to_cli, sc->sopgTable->eth_to_srv,
+                             sc->srmmTable->eth_to_cli, fp);
 }
 
 PORT_GROUP * fpGetServicePortGroupByOrdinal(sopg_table_t *sopg, int proto, int dir, \
int16_t proto_ordinal) @@ -2987,6 +3084,14 @@ PORT_GROUP * \
fpGetServicePortGroupByOrdinal(sopg_table_t *sopg, int proto, int d  
            break;
 
+       case ETH_II_FRAME:
+           if (dir == TO_SERVER)
+               pg = sopg->eth_to_srv[proto_ordinal];
+           else
+               pg = sopg->eth_to_cli[proto_ordinal];
+
+           break;
+
        default:
            break;
    }
@@ -3279,6 +3384,10 @@ void fpShowEventStats(SnortConfig *sc)
     LogMessage("\n");
     LogMessage("** IP Event Stats --\n");
     prmShowEventStats(sc->prmIpRTNX);
+
+    LogMessage("\n");
+    LogMessage("** ETH II Event Stats --\n");
+    prmShowEventStats(sc->prmEthRTNX);
 }
 
 static void fpAddIpProtoOnlyRule(SF_LIST **ip_proto_only_lists, OptTreeNode *otn)
@@ -3338,7 +3447,64 @@ static void fpRegIpProto(uint8_t *ip_proto_array, OptTreeNode \
                *otn)
         FatalError("%s(%d) Error getting ip protocols\n", __FILE__, __LINE__);
 
     for (i = 0; i < NUM_IP_PROTOS; i++)
-        if (ip_protos[i]) ip_proto_array[i] = 1;
+        if (ip_protos[i])
+            ip_proto_array[i] = 1;
+}
+
+static void fpAddRawEthIIRule(SF_LIST **eth_type_only_lists, OptTreeNode *otn)
+{
+    uint8_t etypes[NUM_ETH_TYPES];
+    uint32_t i;
+
+    if (!otn->ds_list[PLUGIN_ETHER_TYPE] || (otn->num_detection_opts != 1))
+            return;
+
+    if (GetEthTypes(otn->ds_list[PLUGIN_ETHER_TYPE], etypes, sizeof(etypes)) != 0)
+        FatalError("Error at %s:%d: Failed to get ethernet types\n",
+                   file_name, file_line);
+
+    for (i = 0; i < NUM_ETH_TYPES; i++)
+    {
+        OptTreeNode *dup;
+
+        if (etypes[i])
+        {
+            if (!eth_type_only_lists[i])
+            {
+                eth_type_only_lists[i] = sflist_new();
+                if (!eth_type_only_lists[i])
+                    FatalError("Error at %s:%d: Could not allocate memory for "
+                               "ether_type array\n", file_name, file_line);
+            }
+
+            /* Search for duplicates. */
+            for (dup = (OptTreeNode *)sflist_first(eth_type_only_lists[i]);
+                 dup != NULL;
+                 dup = (OptTreeNode *)sflist_next(eth_type_only_lists[i]))
+            {
+                if (dup == otn)
+                    return;
+            }
+
+            if (sflist_add_head(eth_type_only_lists[i], otn) != 0)
+                FatalError("Error at %s:%d: Failed to add otn to ether_type \
array\n", +                           file_name, file_line);
+        }
+    }
+}
+
+static void fpRegEthType(uint8_t *eth_type_array, OptTreeNode *otn)
+{
+    uint8_t etypes[NUM_ETH_TYPES];
+    uint32_t i;
+
+    if (GetEthTypes(otn->ds_list[PLUGIN_ETHER_TYPE], etypes, sizeof(etypes)) != 0)
+        FatalError("Error at %s:%d: Failed to get ethernet types\n",
+                   file_name, file_line);
+
+    for (i = 0; i < NUM_ETH_TYPES; i++)
+        if (etypes[i])
+            eth_type_array[i] = 1;
 }
 
 const char * PatternRawToContent(const char *pattern, int pattern_len)
diff --git a/src/fpcreate.h b/src/fpcreate.h
index 4161700..6e26790 100644
--- a/src/fpcreate.h
+++ b/src/fpcreate.h
@@ -137,6 +137,9 @@ typedef struct
   SFGHASH * ip_to_srv;
   SFGHASH * ip_to_cli;
 
+  SFGHASH * eth_to_srv;
+  SFGHASH * eth_to_cli;
+
 } srmm_table_t;
 
 /*
@@ -156,6 +159,9 @@ typedef struct
   PORT_GROUP *ip_to_srv[MAX_PROTOCOL_ORDINAL];
   PORT_GROUP *ip_to_cli[MAX_PROTOCOL_ORDINAL];
 
+  PORT_GROUP *eth_to_srv[MAX_PROTOCOL_ORDINAL];
+  PORT_GROUP *eth_to_cli[MAX_PROTOCOL_ORDINAL];
+
 } sopg_table_t; 
 #endif
 
@@ -184,6 +190,7 @@ int prmFindRuleGroupTcp(PORT_RULE_MAP *, int, int, PORT_GROUP **, \
PORT_GROUP **,  int prmFindRuleGroupUdp(PORT_RULE_MAP *, int, int, PORT_GROUP **, \
PORT_GROUP **, PORT_GROUP **);  int prmFindRuleGroupIp(PORT_RULE_MAP *, int, \
PORT_GROUP **, PORT_GROUP **);  int prmFindRuleGroupIcmp(PORT_RULE_MAP *, int, \
PORT_GROUP **, PORT_GROUP **); +int prmFindRuleGroupEth(PORT_RULE_MAP *, int, \
PORT_GROUP **, PORT_GROUP **);  
 int fpSetDetectSearchMethod(FastPatternConfig *, char *);
 void fpSetDetectSearchOpt(FastPatternConfig *, int flag);
diff --git a/src/fpdetect.c b/src/fpdetect.c
index dde84d5..ba787ff 100644
--- a/src/fpdetect.c
+++ b/src/fpdetect.c
@@ -103,7 +103,7 @@ static inline int fpEvalHeaderIcmp(Packet *p, OTNX_MATCH_DATA *);
 static inline int fpEvalHeaderTcp(Packet *p, OTNX_MATCH_DATA *);
 static inline int fpEvalHeaderUdp(Packet *p, OTNX_MATCH_DATA *);
 static inline int fpEvalHeaderSW(PORT_GROUP *port_group, Packet *p,
-                                 int check_ports, char ip_rule, OTNX_MATCH_DATA *);
+                                 int check_ports, uint8_t rule_type, OTNX_MATCH_DATA \
*);  static int rule_tree_match (void* id, void * tree, int index, void * data, void \
*neg_list );  int fpAddMatch( OTNX_MATCH_DATA *omd_local, OTNX *otnx, int pLen, \
OptTreeNode *otn);  static inline int fpAddSessionAlert(Packet *p, OptTreeNode *otn, \
int alerted); @@ -1044,6 +1044,7 @@ void printRuleFmt1( OptTreeNode * otn )
     else if( rtn->proto== IPPROTO_UDP     )LogMessage("udp  ");
     else if( rtn->proto== IPPROTO_ICMP    )LogMessage("icmp ");
     else if( rtn->proto== ETHERNET_TYPE_IP)LogMessage("ip   ");
+    else if( rtn->proto== ETH_II_FRAME    )LogMessage("eth   ");
 
     LogMessage("gid:%u sid:%5u ", otn->sigInfo.generator,otn->sigInfo.id);
 
@@ -1075,7 +1076,8 @@ void printRuleFmt1( OptTreeNode * otn )
 **    PORT_GROUP * - the port group to inspect
 **    Packet *     - the packet to inspect
 **    int          - whether src/dst ports should be checked (udp/tcp or icmp)
-**    char         - whether the rule is an IP rule (change the packet payload \
pointer) +**    uint8_t      - what the rule type is (other for TCP/UDP/etc, IP, or \
ETH_II). +**                   This sets the packet payload pointer appropriately.
 **
 **  FORMAL OUTPUTS
 **    int - 0 for failed pattern match
@@ -1083,7 +1085,7 @@ void printRuleFmt1( OptTreeNode * otn )
 **
 */
 static inline int fpEvalHeaderSW(PORT_GROUP *port_group, Packet *p,
-        int check_ports, char ip_rule, OTNX_MATCH_DATA *omd)
+        int check_ports, uint8_t rule_type, OTNX_MATCH_DATA *omd)
 {
     RULE_NODE *rnWalk;
     void * so;
@@ -1099,7 +1101,7 @@ static inline int fpEvalHeaderSW(PORT_GROUP *port_group, Packet \
*p,  FastPatternConfig *fp = snort_conf->fast_pattern_config;
     PROFILE_VARS;
 
-    if (ip_rule)
+    if (rule_type == SW_RULE_TYPE_IP)
     {
         /* Set the packet payload pointers to that of IP,
          ** since this is an IP rule. */
@@ -1127,9 +1129,19 @@ static inline int fpEvalHeaderSW(PORT_GROUP *port_group, \
Packet *p,  }
         }
     }
+    else if (rule_type == SW_RULE_TYPE_ETH)
+    {
+        if (p->eth_data)
+        {
+            p->data = p->eth_data;
+            p->dsize = p->eth_dsize;
+            p->packet_flags |= PKT_ETH_II_RULE;
+        }
+    }
     else
     {
         p->packet_flags &= ~PKT_IP_RULE;
+        p->packet_flags &= ~PKT_ETH_II_RULE;
     }
 
     /*
@@ -1348,7 +1360,7 @@ static inline int fpEvalHeaderSW(PORT_GROUP *port_group, Packet \
*p,  }
 
 #ifdef GRE
-        if (ip_rule && p->outer_ip_data)
+        if ((rule_type == SW_RULE_TYPE_IP) && p->outer_ip_data)
         {
             /* Evaluate again with the inner IPs */
             p->iph = p->inner_iph;
@@ -1370,7 +1382,7 @@ static inline int fpEvalHeaderSW(PORT_GROUP *port_group, Packet \
*p,  #ifdef PPM_MGR  /* Tag only used with PPM right now */
 fp_eval_header_sw_reset_ip:
 #endif
-    if (ip_rule)
+    if (rule_type == SW_RULE_TYPE_IP)
     {
         /* Set the data & dsize back to original values. */
         p->iph = tmp_iph;
@@ -1442,19 +1454,19 @@ static inline int fpEvalHeaderUdp(Packet *p, OTNX_MATCH_DATA \
*omd)  
     if (dst != NULL)
     {
-        if (fpEvalHeaderSW(dst, p, 1, 0, omd))
+        if (fpEvalHeaderSW(dst, p, 1, SW_RULE_TYPE_OTHER, omd))
             return 1;
     }
 
     if (src != NULL)
     {
-        if (fpEvalHeaderSW(src, p, 1, 0, omd))
+        if (fpEvalHeaderSW(src, p, 1, SW_RULE_TYPE_OTHER, omd))
             return 1;
     }
 
     if (gen != NULL)
     {
-        if (fpEvalHeaderSW(gen, p, 1, 0, omd))
+        if (fpEvalHeaderSW(gen, p, 1, SW_RULE_TYPE_OTHER, omd))
             return 1;
     }
 
@@ -1526,19 +1538,19 @@ static inline int fpEvalHeaderTcp(Packet *p, OTNX_MATCH_DATA \
*omd)  
     if (dst != NULL)
     {
-        if (fpEvalHeaderSW(dst, p, 1, 0, omd))
+        if (fpEvalHeaderSW(dst, p, 1, SW_RULE_TYPE_OTHER, omd))
             return 1;
     }
 
     if (src != NULL)
     {
-        if (fpEvalHeaderSW(src, p, 1, 0, omd))
+        if (fpEvalHeaderSW(src, p, 1, SW_RULE_TYPE_OTHER, omd))
             return 1;
     }
 
     if (gen != NULL)
     {
-        if(fpEvalHeaderSW(gen, p, 1, 0, omd))
+        if(fpEvalHeaderSW(gen, p, 1, SW_RULE_TYPE_OTHER, omd))
             return 1;
     }
 
@@ -1566,13 +1578,13 @@ static inline int fpEvalHeaderIcmp(Packet *p, OTNX_MATCH_DATA \
*omd)  
     if (type != NULL)
     {
-        if (fpEvalHeaderSW(type, p, 0, 0, omd))
+        if (fpEvalHeaderSW(type, p, 0, SW_RULE_TYPE_OTHER, omd))
             return 1;
     }
 
     if (gen != NULL)
     {
-        if (fpEvalHeaderSW(gen, p, 0, 0, omd))
+        if (fpEvalHeaderSW(gen, p, 0, SW_RULE_TYPE_OTHER, omd))
             return 1;
     }
 
@@ -1596,13 +1608,43 @@ static inline int fpEvalHeaderIp(Packet *p, int ip_proto, \
OTNX_MATCH_DATA *omd)  
     if (ip_group != NULL)
     {
-        if (fpEvalHeaderSW(ip_group, p, 0, 1, omd))
+        if (fpEvalHeaderSW(ip_group, p, 0, SW_RULE_TYPE_IP, omd))
             return 1;
     }
 
     if (gen != NULL)
     {
-        if (fpEvalHeaderSW(gen, p, 0, 1, omd))
+        if (fpEvalHeaderSW(gen, p, 0, SW_RULE_TYPE_IP, omd))
+            return 1;
+    }
+
+    return fpFinalSelectEvent(omd, p);
+}
+
+/*
+**  fpEvalHeaderEth::
+*/
+static inline int fpEvalHeaderEth(Packet *p, int eth_type, OTNX_MATCH_DATA *omd)
+{
+    PORT_GROUP *gen = NULL, *eth_group = NULL;
+
+    if (!prmFindRuleGroupEth(snort_conf->prmEthRTNX, eth_type, &eth_group, &gen))
+        return 0;
+
+    if(fpDetectGetDebugPrintNcRules(snort_conf->fast_pattern_config))
+        LogMessage("fpEvalHeaderEth: eth_group=%p, gen=%p\n", (void*)eth_group, \
(void*)gen); +
+    InitMatchInfo(omd);
+
+    if (eth_group)
+    {
+        if (fpEvalHeaderSW(eth_group, p, 0, SW_RULE_TYPE_ETH, omd))
+            return 1;
+    }
+
+    if (gen)
+    {
+        if (fpEvalHeaderSW(gen, p, 0, SW_RULE_TYPE_ETH, omd))
             return 1;
     }
 
@@ -1620,9 +1662,10 @@ static inline int fpEvalHeaderIp(Packet *p, int ip_proto, \
                OTNX_MATCH_DATA *omd)
 **    process the both that particular ruleset and the IP ruleset
 **    with in the fpEvalHeader for that protocol.  If the protocol
 **    is not TCP, UDP, or ICMP, we just process the packet against
-**    the IP rules at the end of the fpEvalPacket routine.  Since
-**    we are using a setwise methodology for snort rules, both the
-**    network layer rules and the transport layer rules are done
+**    any IP or ETH rules at the end of the fpEvalPacket routine.
+**
+**    Since we are using a setwise methodology for snort rules, both
+**    the network layer rules and the transport layer rules are done
 **    at the same time.  While this is not the best for modularity,
 **    it is the best for performance, which is what we are working
 **    on currently.
@@ -1636,86 +1679,99 @@ static inline int fpEvalHeaderIp(Packet *p, int ip_proto, \
                OTNX_MATCH_DATA *omd)
 */
 int fpEvalPacket(Packet *p)
 {
-    int ip_proto = GET_IPH_PROTO(p);
     OTNX_MATCH_DATA *omd = snort_conf->omd;
 
-    /* Run UDP rules against the UDP header of Teredo packets */
-    if ( p->udph && (p->proto_bits & (PROTO_BIT__TEREDO | PROTO_BIT__GTP)) )
+    if (IPH_IS_VALID(p))
     {
-        uint16_t tmp_sp = p->sp;
-        uint16_t tmp_dp = p->dp;
-        const UDPHdr *tmp_udph = p->udph;
-        const uint8_t *tmp_data = p->data;
-        uint16_t tmp_dsize = p->dsize;
+        int ip_proto = GET_IPH_PROTO(p);
 
-        if (p->outer_udph)
+        /* Run UDP rules against the UDP header of Teredo packets */
+        if ( p->udph && (p->proto_bits & (PROTO_BIT__TEREDO | PROTO_BIT__GTP)) )
         {
-            p->udph = p->outer_udph;
-        }
-        p->sp = ntohs(p->udph->uh_sport);
-        p->dp = ntohs(p->udph->uh_dport);
-        p->data = (const uint8_t *)p->udph + UDP_HEADER_LEN;
-        if (p->outer_ip_dsize >  UDP_HEADER_LEN)
-            p->dsize = p->outer_ip_dsize - UDP_HEADER_LEN;
-
-        fpEvalHeaderUdp(p, omd);
-
-        p->sp = tmp_sp;
-        p->dp = tmp_dp;
-        p->udph = tmp_udph;
-        p->data = tmp_data;
-        p->dsize = tmp_dsize;
-    }
-
-    switch(ip_proto)
-    {
-        case IPPROTO_TCP:
-            DEBUG_WRAP(DebugMessage(DEBUG_DETECT,
-                        "Detecting on TcpList\n"););
+            uint16_t tmp_sp = p->sp;
+            uint16_t tmp_dp = p->dp;
+            const UDPHdr *tmp_udph = p->udph;
+            const uint8_t *tmp_data = p->data;
+            uint16_t tmp_dsize = p->dsize;
 
-            if(p->tcph == NULL)
+            if (p->outer_udph)
             {
-                ip_proto = -1;
-                break;
+                p->udph = p->outer_udph;
             }
+            p->sp = ntohs(p->udph->uh_sport);
+            p->dp = ntohs(p->udph->uh_dport);
+            p->data = (const uint8_t *)p->udph + UDP_HEADER_LEN;
+            if (p->outer_ip_dsize >  UDP_HEADER_LEN)
+                p->dsize = p->outer_ip_dsize - UDP_HEADER_LEN;
+
+            fpEvalHeaderUdp(p, omd);
+
+            p->sp = tmp_sp;
+            p->dp = tmp_dp;
+            p->udph = tmp_udph;
+            p->data = tmp_data;
+            p->dsize = tmp_dsize;
+        }
 
-            return fpEvalHeaderTcp(p, omd);
+        switch(ip_proto)
+        {
+            case IPPROTO_TCP:
+                DEBUG_WRAP(DebugMessage(DEBUG_DETECT,
+                            "Detecting on TcpList\n"););
 
-        case IPPROTO_UDP:
-            DEBUG_WRAP(DebugMessage(DEBUG_DETECT,
-                        "Detecting on UdpList\n"););
+                if(p->tcph == NULL)
+                {
+                    ip_proto = -1;
+                    break;
+                }
 
-            if(p->udph == NULL)
-            {
-                ip_proto = -1;
-                break;
-            }
+                return fpEvalHeaderTcp(p, omd);
+
+            case IPPROTO_UDP:
+                DEBUG_WRAP(DebugMessage(DEBUG_DETECT,
+                            "Detecting on UdpList\n"););
+
+                if(p->udph == NULL)
+                {
+                    ip_proto = -1;
+                    break;
+                }
 
-            return fpEvalHeaderUdp(p, omd);
+                return fpEvalHeaderUdp(p, omd);
 
 #ifdef SUP_IP6
-        case IPPROTO_ICMPV6:
+            case IPPROTO_ICMPV6:
 #endif
-        case IPPROTO_ICMP:
-            DEBUG_WRAP(DebugMessage(DEBUG_DETECT,
-                        "Detecting on IcmpList\n"););
+            case IPPROTO_ICMP:
+                DEBUG_WRAP(DebugMessage(DEBUG_DETECT,
+                            "Detecting on IcmpList\n"););
 
-            if(p->icmph == NULL)
-            {
-                ip_proto = -1;
+                if(p->icmph == NULL)
+                {
+                    ip_proto = -1;
+                    break;
+                }
+
+                return fpEvalHeaderIcmp(p, omd);
+
+            default:
                 break;
-            }
+        }
 
-            return fpEvalHeaderIcmp(p, omd);
+        /*
+        **  No Match on TCP/UDP, Do IP
+        */
+        return fpEvalHeaderIp(p, ip_proto, omd);
+    }
+    else if (p->eh)
+    {
+        /* Raw Ethernet II Frame */
+        int eth_type = (int)p->eth_type;
 
-        default:
-            break;
+        return fpEvalHeaderEth(p, eth_type, omd);
     }
 
-    /*
-    **  No Match on TCP/UDP, Do IP
-    */
-    return fpEvalHeaderIp(p, ip_proto, omd);
+    return 0;
 }
 
 void fpEvalIpProtoOnlyRules(SF_LIST **ip_proto_only_lists, Packet *p)
@@ -1748,3 +1804,32 @@ void fpEvalIpProtoOnlyRules(SF_LIST **ip_proto_only_lists, \
Packet *p)  }
 }
 
+void fpEvalEtherTypeOnlyRules(SF_LIST **eth_type_only_lists, Packet *p)
+{
+    if (p && p->eh)
+    {
+        SF_LIST *l = eth_type_only_lists[p->eth_type];
+        OptTreeNode *otn;
+
+        /* If list is NULL, sflist_first returns NULL */
+        for (otn = (OptTreeNode *)sflist_first(l);
+             otn != NULL;
+             otn = (OptTreeNode *)sflist_next(l))
+        {
+            if (fpEvalRTN(getRuntimeRtnFromOtn(otn), p, 0))
+            {
+                SnortEventqAdd(otn->sigInfo.generator,
+                               otn->sigInfo.id,
+                               otn->sigInfo.rev,
+                               otn->sigInfo.class_id,
+                               otn->sigInfo.priority,
+                               otn->sigInfo.message,
+                               (void *)NULL);
+                if (RULE_TYPE__PASS == getRuntimeRtnFromOtn(otn)->type)
+                {
+                    p->packet_flags |= PKT_PASS_RULE;
+                }
+            }
+        }
+    }
+}
diff --git a/src/fpdetect.h b/src/fpdetect.h
index e92928c..3a39f7b 100644
--- a/src/fpdetect.h
+++ b/src/fpdetect.h
@@ -43,6 +43,17 @@
 #define REBUILD_FLAGS (PKT_REBUILT_FRAG | PKT_REBUILT_STREAM)
 
 /*
+ * Prior to adding ethernet II frame detection, fpEvalHeaderSW took a
+ * boolean value to state if it was an IP-only rule so that the appropriate
+ * pointers could be setup.  Rather than add an extra argument to the
+ * fpEvalHeaderSW function, we'll just change the 'char ip_rule' argument
+ * into 'uint8_t rule_type' to select between different rule types.
+ */
+#define SW_RULE_TYPE_OTHER      0x00        /* TCP/UDP/ICMP */
+#define SW_RULE_TYPE_IP         0x01        /* IP */
+#define SW_RULE_TYPE_ETH        0x02        /* ETH_II */
+
+/*
 **  This is the only function that is needed to do an
 **  inspection on a packet.
 */
@@ -98,6 +109,7 @@ void OtnxMatchDataFree(OTNX_MATCH_DATA *);
 int fpAddMatch( OTNX_MATCH_DATA *omd_local, OTNX *otnx, int pLen,
                 OptTreeNode *otn);
 void fpEvalIpProtoOnlyRules(SF_LIST **, Packet *);
+void fpEvalEtherTypeOnlyRules(SF_LIST **, Packet *);
 
 #define TO_SERVER 1
 #define TO_CLIENT 0
diff --git a/src/parser.c b/src/parser.c
index 805262e..5c83633 100644
--- a/src/parser.c
+++ b/src/parser.c
@@ -80,6 +80,7 @@
 #include "sp_preprocopt.h"
 #include "detection-plugins/sp_icmp_type_check.h"
 #include "detection-plugins/sp_ip_proto.h"
+#include "detection-plugins/sp_ether_type.h"
 #include "detection-plugins/sp_pattern_match.h"
 #include "sf_vartable.h"
 #include "ipv6_port.h"
@@ -130,6 +131,7 @@
 #define RULE_PROTO_OPT__TCP   "tcp"
 #define RULE_PROTO_OPT__UDP   "udp"
 #define RULE_PROTO_OPT__ICMP  "icmp"
+#define RULE_PROTO_OPT__ETH   "eth"
 
 #define RULE_DIR_OPT__DIRECTIONAL    "->"
 #define RULE_DIR_OPT__BIDIRECTIONAL  "<>"
@@ -462,6 +464,7 @@ static rule_count_t tcpCnt;
 static rule_count_t udpCnt;
 static rule_count_t icmpCnt;
 static rule_count_t ipCnt;
+static rule_count_t ethCnt;
 
 rule_index_map_t *ruleIndexMap = NULL;   /* rule index -> sid:gid map */
 
@@ -921,6 +924,7 @@ SnortConfig * ParseSnortConf(void)
     sc->rate_filter_config = RateFilter_ConfigNew();
     sc->detection_filter_config = DetectionFilterConfigNew();
     sc->ip_proto_only_lists = (SF_LIST **)SnortAlloc(NUM_IP_PROTOS * sizeof(SF_LIST \
*)); +    sc->eth_type_only_lists = (SF_LIST **)SnortAlloc(NUM_ETH_TYPES * \
sizeof(SF_LIST *));  
     /* We're not going to parse rules on the first pass */
     parse_rules = 0;
@@ -1208,6 +1212,7 @@ static void DumpRuleChains(RuleListNode *rule_lists)
 
     while (rule != NULL)
     {
+        DumpChain(rule->name, rule->mode, ETH_II_FRAME);
         DumpChain(rule->name, rule->mode, ETHERNET_TYPE_IP);
         DumpChain(rule->name, rule->mode, IPPROTO_TCP);
         DumpChain(rule->name, rule->mode, IPPROTO_UDP);
@@ -1313,43 +1318,55 @@ static int FinishPortListRule(rule_port_tables_t \
*port_tables, RuleTreeNode *rtn  PortObject *ncObject;
     rule_count_t *prc;
 
-    /* Select the Target PortTable for this rule, based on protocol, src/dst
-     * dir, and if there is rule content */
-    if (proto == IPPROTO_TCP)
-    {
-        dstTable = port_tables->tcp_dst;
-        srcTable = port_tables->tcp_src;
-        aaObject = port_tables->tcp_anyany;
-        ncObject = port_tables->tcp_nocontent;
-        prc = &tcpCnt;
-    }
-    else if (proto == IPPROTO_UDP)
-    {
-        dstTable = port_tables->udp_dst;
-        srcTable = port_tables->udp_src;
-        aaObject = port_tables->udp_anyany;
-        ncObject = port_tables->udp_nocontent;
-        prc = &udpCnt;
-    }
-    else if (proto == IPPROTO_ICMP)
-    {
-        dstTable = port_tables->icmp_dst;
-        srcTable = port_tables->icmp_src;
-        aaObject = port_tables->icmp_anyany;
-        ncObject = port_tables->icmp_nocontent;
-        prc = &icmpCnt;
-    }
-    else if (proto == ETHERNET_TYPE_IP)
-    {
-        dstTable = port_tables->ip_dst;
-        srcTable = port_tables->ip_src;
-        aaObject = port_tables->ip_anyany;
-        ncObject = port_tables->ip_nocontent;
-        prc = &ipCnt;
-    }
-    else
-    {
-        return -1;
+    /*
+     * Select the Target PortTable for this rule, based on protocol, src/dst
+     * dir, and if there is rule content
+     */
+    switch (proto)
+    {
+        case IPPROTO_TCP:
+            dstTable = port_tables->tcp_dst;
+            srcTable = port_tables->tcp_src;
+            aaObject = port_tables->tcp_anyany;
+            ncObject = port_tables->tcp_nocontent;
+            prc = &tcpCnt;
+            break;
+
+        case IPPROTO_UDP:
+            dstTable = port_tables->udp_dst;
+            srcTable = port_tables->udp_src;
+            aaObject = port_tables->udp_anyany;
+            ncObject = port_tables->udp_nocontent;
+            prc = &udpCnt;
+            break;
+
+        case IPPROTO_ICMP:
+            dstTable = port_tables->icmp_dst;
+            srcTable = port_tables->icmp_src;
+            aaObject = port_tables->icmp_anyany;
+            ncObject = port_tables->icmp_nocontent;
+            prc = &icmpCnt;
+            break;
+
+        case ETHERNET_TYPE_IP:
+            dstTable = port_tables->ip_dst;
+            srcTable = port_tables->ip_src;
+            aaObject = port_tables->ip_anyany;
+            ncObject = port_tables->ip_nocontent;
+            prc = &ipCnt;
+            break;
+
+        case ETH_II_FRAME:
+            dstTable = port_tables->eth_dst;
+            srcTable = port_tables->eth_src;
+            aaObject = port_tables->eth_anyany;
+            ncObject = port_tables->eth_nocontent;
+            prc = &ethCnt;
+            break;
+
+        default:
+            return -1;
+            break;
     }
 
     /* Count rules with both src and dst specific ports */
@@ -1464,6 +1481,12 @@ static int FinishPortListRule(rule_port_tables_t *port_tables, \
RuleTreeNode *rtn  PortObjectAddRule(aaObject, rim_index);
             prc->aa++;
         }
+        else if (proto == ETH_II_FRAME)
+        {
+            PortObjectAddRule(port_tables->eth_anyany, rim_index);
+            ethCnt.aa++;
+            prc->aa++;
+        }
         else
         {
             /* For other protocols-tcp/udp/icmp add to the any any group */
@@ -3237,6 +3260,10 @@ static int GetRuleProtocol(char *proto_str)
     {
         return ETHERNET_TYPE_IP;
     }
+    else if (strcasecmp(proto_str, RULE_PROTO_OPT__ETH) == 0)
+    {
+        return ETH_II_FRAME;
+    }
     else
     {
         /* If we've gotten here, we have a protocol string we didn't recognize
@@ -5026,7 +5053,8 @@ int CheckRuleStates(SnortConfig *sc)
             }
 
             if ((rtn->proto == IPPROTO_TCP) || (rtn->proto == IPPROTO_UDP) ||
-                (rtn->proto == IPPROTO_ICMP) || (rtn->proto == ETHERNET_TYPE_IP))
+                (rtn->proto == IPPROTO_ICMP) || (rtn->proto == ETHERNET_TYPE_IP) ||
+                (rtn->proto == ETH_II_FRAME))
             {
                 //do operation
                 if ( otn->sigInfo.shared )
@@ -5996,6 +6024,7 @@ static void InitParser(void)
     memset(&udpCnt, 0, sizeof(udpCnt));
     memset(&ipCnt, 0, sizeof(ipCnt));
     memset(&icmpCnt, 0, sizeof(icmpCnt));
+    memset(&ethCnt, 0, sizeof(ethCnt));
 
     port_list_free(&port_list);
     memset(&port_list, 0, sizeof(port_list));
@@ -6085,12 +6114,12 @@ void ParseRules(SnortConfig *sc)
     PortTablesFinish(sc->port_tables, sc->fast_pattern_config);
 
     LogMessage("+-------------------[Rule Port \
                Counts]---------------------------------------\n");
-    LogMessage("|%8s%8s%8s%8s%8s\n", " ", "tcp", "udp", "icmp", "ip");
-    LogMessage("|%8s%8u%8u%8u%8u\n", "src", tcpCnt.src, udpCnt.src, icmpCnt.src, \
                ipCnt.src);
-    LogMessage("|%8s%8u%8u%8u%8u\n", "dst", tcpCnt.dst, udpCnt.dst, icmpCnt.dst, \
                ipCnt.dst);
-    LogMessage("|%8s%8u%8u%8u%8u\n", "any", tcpCnt.aa, udpCnt.aa, icmpCnt.aa, \
                ipCnt.aa);
-    LogMessage("|%8s%8u%8u%8u%8u\n", "nc", tcpCnt.nc, udpCnt.nc, icmpCnt.nc, \
                ipCnt.nc);
-    LogMessage("|%8s%8u%8u%8u%8u\n", "s+d", tcpCnt.sd, udpCnt.sd, icmpCnt.sd, \
ipCnt.sd); +    LogMessage("|%8s%8s%8s%8s%8s%8s\n", " ", "tcp", "udp", "icmp", "ip", \
"eth"); +    LogMessage("|%8s%8u%8u%8u%8u%8u\n", "src", tcpCnt.src, udpCnt.src, \
icmpCnt.src, ipCnt.src, ethCnt.src); +    LogMessage("|%8s%8u%8u%8u%8u%8u\n", "dst", \
tcpCnt.dst, udpCnt.dst, icmpCnt.dst, ipCnt.dst, ethCnt.dst); +    \
LogMessage("|%8s%8u%8u%8u%8u%8u\n", "any", tcpCnt.aa, udpCnt.aa, icmpCnt.aa, \
ipCnt.aa, ethCnt.aa); +    LogMessage("|%8s%8u%8u%8u%8u%8u\n", "nc", tcpCnt.nc, \
udpCnt.nc, icmpCnt.nc, ipCnt.nc, ethCnt.nc); +    LogMessage("|%8s%8u%8u%8u%8u%8u\n", \
                "s+d", tcpCnt.sd, udpCnt.sd, icmpCnt.sd, ipCnt.sd, ethCnt.sd);
     LogMessage("+----------------------------------------------------------------------------\n");
  
     ///print_rule_index_map( ruleIndexMap );
@@ -9468,16 +9497,27 @@ static void ParseRule(SnortConfig *sc, SnortPolicy *p, char \
*args,  case IPPROTO_TCP:
                 sc->ip_proto_array[IPPROTO_TCP] = 1;
                 break;
+
             case IPPROTO_UDP:
                 sc->ip_proto_array[IPPROTO_UDP] = 1;
                 break;
+
             case IPPROTO_ICMP:
                 sc->ip_proto_array[IPPROTO_ICMP] = 1;
                 sc->ip_proto_array[IPPROTO_ICMPV6] = 1;
                 break;
+
             case ETHERNET_TYPE_IP:
                 /* This will be set via ip_protos */
                 break;
+
+            case ETH_II_FRAME:
+                /*
+                 * This will configure sc->eth_type_array instead, via a call
+                 * into GetEthTypes in src/detection-plugins/esp_ether_type.c.
+                 */
+                break;
+
             default:
                 ParseError("Bad protocol: %s", toks[0]);
                 break;
@@ -11483,24 +11523,29 @@ static rule_port_tables_t * PortTablesNew(void)
     /* No content rule objects */
     rpt->tcp_nocontent = PortObjectNew();
     if (rpt->tcp_nocontent == NULL)
-        FatalError("ParseRulesFile nocontent PortObjectNew() failed\n");
+        FatalError("ParseRulesFile tcp nocontent PortObjectNew() failed\n");
     PortObjectAddPortAny(rpt->tcp_nocontent);
 
     rpt->udp_nocontent = PortObjectNew();
     if (rpt->udp_nocontent == NULL)
-        FatalError("ParseRulesFile nocontent PortObjectNew() failed\n");
+        FatalError("ParseRulesFile udp nocontent PortObjectNew() failed\n");
     PortObjectAddPortAny(rpt->udp_nocontent);
 
     rpt->icmp_nocontent = PortObjectNew();
     if (rpt->icmp_nocontent == NULL)
-        FatalError("ParseRulesFile nocontent PortObjectNew() failed\n");
+        FatalError("ParseRulesFile icmp nocontent PortObjectNew() failed\n");
     PortObjectAddPortAny(rpt->icmp_nocontent);
 
     rpt->ip_nocontent = PortObjectNew();
     if (rpt->ip_nocontent == NULL)
-        FatalError("ParseRulesFile nocontent PortObjectNew() failed\n");
+        FatalError("ParseRulesFile ip nocontent PortObjectNew() failed\n");
     PortObjectAddPortAny(rpt->ip_nocontent);
 
+    rpt->eth_nocontent = PortObjectNew();
+    if (rpt->eth_nocontent == NULL)
+        FatalError("ParseRulesFile eth nocontent PortObjectNew() failed\n");
+    PortObjectAddPortAny(rpt->eth_nocontent);
+
     /* Create the Any-Any Port Objects for each protocol */
     rpt->tcp_anyany = PortObjectNew();
     if (rpt->tcp_anyany == NULL)
@@ -11522,6 +11567,11 @@ static rule_port_tables_t * PortTablesNew(void)
         FatalError("ParseRulesFile ip PortObjectNew() failed\n");
     PortObjectAddPortAny(rpt->ip_anyany);
 
+    rpt->eth_anyany = PortObjectNew();
+    if (rpt->eth_anyany == NULL)
+        FatalError("ParseRulesFile eth PortObjectNew() failed\n");
+    PortObjectAddPortAny(rpt->eth_anyany);
+
     /* Create the tcp Rules PortTables */
     rpt->tcp_src = PortTableNew();
     if (rpt->tcp_src == NULL)
@@ -11558,6 +11608,15 @@ static rule_port_tables_t * PortTablesNew(void)
     if (rpt->ip_dst == NULL)
         FatalError("ParseRulesFile ip-dst PortTableNew() failed\n");
 
+    /* Create the eth Rules PortTables */
+    rpt->eth_src = PortTableNew();
+    if (rpt->eth_src == NULL)
+        FatalError("ParseRulesFile eth-src PortTableNew() failed\n");
+
+    rpt->eth_dst = PortTableNew();
+    if (rpt->eth_dst == NULL)
+        FatalError("ParseRulesFile eth-dst PortTableNew() failed\n");
+
     /*
      * someday these could be read from snort.conf, something like...
      * 'config portlist: large-rule-count <val>'
@@ -11570,6 +11629,8 @@ static rule_port_tables_t * PortTablesNew(void)
     rpt->icmp_dst->pt_lrc= DEFAULT_LARGE_RULE_GROUP;
     rpt->ip_src->pt_lrc  = DEFAULT_LARGE_RULE_GROUP;
     rpt->ip_dst->pt_lrc  = DEFAULT_LARGE_RULE_GROUP;
+    rpt->eth_src->pt_lrc  = DEFAULT_LARGE_RULE_GROUP;
+    rpt->eth_dst->pt_lrc  = DEFAULT_LARGE_RULE_GROUP;
 
     return rpt;
 }
@@ -11620,14 +11681,27 @@ static void PortTablesFinish(rule_port_tables_t \
*port_tables, FastPatternConfig  finish_portlist_table(fp, "ip src", \
port_tables->ip_src);  finish_portlist_table(fp, "ip dst", port_tables->ip_dst);
 
+    /* ETH-SRC */
+    if (fpDetectGetDebugPrintRuleGroupsCompiled(fp))
+    {
+        LogMessage("ETH-Any-Any Port List\n");
+        PortObjectPrintEx(port_tables->eth_anyany,
+                          rule_index_map_print_index);
+    }
+
+    finish_portlist_table(fp, "eth src", port_tables->eth_src);
+    finish_portlist_table(fp, "eth dst", port_tables->eth_dst);
+
     RuleListSortUniq(port_tables->tcp_anyany->rule_list);
     RuleListSortUniq(port_tables->udp_anyany->rule_list);
     RuleListSortUniq(port_tables->icmp_anyany->rule_list);
     RuleListSortUniq(port_tables->ip_anyany->rule_list);
+    RuleListSortUniq(port_tables->eth_anyany->rule_list);
     RuleListSortUniq(port_tables->tcp_nocontent->rule_list);
     RuleListSortUniq(port_tables->udp_nocontent->rule_list);
     RuleListSortUniq(port_tables->icmp_nocontent->rule_list);
     RuleListSortUniq(port_tables->ip_nocontent->rule_list);
+    RuleListSortUniq(port_tables->eth_nocontent->rule_list);
 }
 
 void VarTablesFree(SnortConfig *sc)
@@ -11693,6 +11767,10 @@ void PortTablesFree(rule_port_tables_t *port_tables)
         PortTableFree(port_tables->ip_src);
     if (port_tables->ip_dst)
         PortTableFree(port_tables->ip_dst);
+    if (port_tables->eth_src)
+        PortTableFree(port_tables->eth_src);
+    if (port_tables->eth_dst)
+        PortTableFree(port_tables->eth_dst);
 
     if (port_tables->tcp_anyany)
         PortObjectFree(port_tables->tcp_anyany);
@@ -11702,6 +11780,8 @@ void PortTablesFree(rule_port_tables_t *port_tables)
         PortObjectFree(port_tables->icmp_anyany);
     if (port_tables->ip_anyany)
         PortObjectFree(port_tables->ip_anyany);
+    if (port_tables->eth_anyany)
+        PortObjectFree(port_tables->eth_anyany);
 
     if (port_tables->tcp_nocontent)
         PortObjectFree(port_tables->tcp_nocontent);
@@ -11711,6 +11791,8 @@ void PortTablesFree(rule_port_tables_t *port_tables)
         PortObjectFree(port_tables->icmp_nocontent);
     if (port_tables->ip_nocontent)
         PortObjectFree(port_tables->ip_nocontent);
+    if (port_tables->eth_nocontent)
+        PortObjectFree(port_tables->eth_nocontent);
 
     free(port_tables);
 }
@@ -12241,7 +12323,8 @@ static void IntegrityCheckRules(SnortConfig *sc)
             }
 
             if ((rtn->proto == IPPROTO_TCP) || (rtn->proto == IPPROTO_UDP)
-                    || (rtn->proto == IPPROTO_ICMP) || (rtn->proto == \
ETHERNET_TYPE_IP)) +                    || (rtn->proto == IPPROTO_ICMP) || \
(rtn->proto == ETHERNET_TYPE_IP) +                    || (rtn->proto == \
ETH_II_FRAME))  {
                 //do operation
                 ofl_idx = otn->opt_func;
@@ -12255,9 +12338,7 @@ static void IntegrityCheckRules(SnortConfig *sc)
                 }
 
                 if(opt_func_count == 0)
-                {
                     FatalError("Zero Length OTN List\n");
-                }
                 //DEBUG_WRAP(DebugMessage(DEBUG_DETECT,"\n"););
 
             }
diff --git a/src/plugbase.c b/src/plugbase.c
index f3a2100..4b12bd1 100644
--- a/src/plugbase.c
+++ b/src/plugbase.c
@@ -94,6 +94,7 @@
 #include "detection-plugins/sp_base64_data.h"
 #include "detection-plugins/sp_pkt_data.h"
 #include "detection-plugins/sp_asn1.h"
+#include "detection-plugins/sp_ether_type.h"
 #ifdef ENABLE_REACT
 #include "detection-plugins/sp_react.h"
 #endif
@@ -210,6 +211,7 @@ void RegisterRuleOptions(void)
     SetupFTPBounce();
     SetupUriLenCheck();
     SetupCvs();
+    EtherTypeSetup();
 }
 
 /****************************************************************************
diff --git a/src/plugin_enum.h b/src/plugin_enum.h
index 6e897cd..f240a9e 100644
--- a/src/plugin_enum.h
+++ b/src/plugin_enum.h
@@ -62,6 +62,7 @@ enum {
     PLUGIN_FLOWBIT,
     PLUGIN_FILE_DATA,
     PLUGIN_BASE64_DECODE,
+    PLUGIN_ETHER_TYPE,
     PLUGIN_MAX  /* sentinel value */
 };
 
diff --git a/src/rule_option_types.h b/src/rule_option_types.h
index d1bbe61..9b31da6 100644
--- a/src/rule_option_types.h
+++ b/src/rule_option_types.h
@@ -64,7 +64,8 @@ typedef enum _option_type_t
     RULE_OPTION_TYPE_TCP_SEQ,
     RULE_OPTION_TYPE_TCP_WIN,
     RULE_OPTION_TYPE_TTL,
-    RULE_OPTION_TYPE_URILEN
+    RULE_OPTION_TYPE_URILEN,
+    RULE_OPTION_TYPE_ETHER_TYPE
 #ifdef DYNAMIC_PLUGIN
     ,
     RULE_OPTION_TYPE_HDR_OPT_CHECK,
diff --git a/src/sfutil/sfportobject.h b/src/sfutil/sfportobject.h
index 209228d..100482b 100644
--- a/src/sfutil/sfportobject.h
+++ b/src/sfutil/sfportobject.h
@@ -161,24 +161,27 @@ typedef struct _PortTable_s {
 
 }PortTable;
 
-typedef struct {
+typedef struct _rule_port_tables_t {
 
     PortTable * tcp_src, * tcp_dst;
     PortTable * udp_src, * udp_dst;
     PortTable * icmp_src,* icmp_dst;
     PortTable * ip_src,  * ip_dst;
+    PortTable * eth_src, * eth_dst;
     
     PortObject * tcp_anyany;
     PortObject * udp_anyany;
     PortObject * icmp_anyany;
     PortObject * ip_anyany;
+    PortObject * eth_anyany;
     
     PortObject * tcp_nocontent; 
     PortObject * udp_nocontent; 
     PortObject * icmp_nocontent; 
     PortObject * ip_nocontent; 
+    PortObject * eth_nocontent;
 
-}rule_port_tables_t;
+} rule_port_tables_t;
 
 
 #define POPERR_NO_NAME            1
diff --git a/src/snort.c b/src/snort.c
index 6b3eeee..273a163 100644
--- a/src/snort.c
+++ b/src/snort.c
@@ -3810,9 +3810,9 @@ void SnortConfFree(SnortConfig *sc)
     if ( sc->event_queue )
         SnortEventqFree(sc->event_queue);
 
-    if (sc->ip_proto_only_lists != NULL)
+    if (sc->ip_proto_only_lists)
     {
-        unsigned int j;
+        uint32_t j;
 
         for (j = 0; j < NUM_IP_PROTOS; j++)
             sflist_free_all(sc->ip_proto_only_lists[j], NULL);
@@ -3820,6 +3820,16 @@ void SnortConfFree(SnortConfig *sc)
         free(sc->ip_proto_only_lists);
     }
 
+    if (sc->eth_type_only_lists)
+    {
+        uint32_t j;
+
+        for (j = 0; j < NUM_ETH_TYPES; j++)
+            sflist_free_all(sc->eth_type_only_lists[j], NULL);
+
+        free(sc->eth_type_only_lists);
+    }
+
 #if defined(SNORT_RELOAD) && !defined(WIN32)
     FreePreprocReloadVerifyFuncList(sc->preproc_reload_verify_funcs);
 #endif
diff --git a/src/snort.h b/src/snort.h
index ede94d1..882c33a 100644
--- a/src/snort.h
+++ b/src/snort.h
@@ -794,6 +794,9 @@ typedef struct _SnortConfig
     SF_LIST **ip_proto_only_lists;
     uint8_t ip_proto_array[NUM_IP_PROTOS];
 
+    SF_LIST **eth_type_only_lists;
+    uint8_t eth_type_array[NUM_ETH_TYPES];
+
     int num_rule_types;
     RuleListNode *rule_lists;
     int evalOrder[RULE_TYPE__MAX + 1];
@@ -833,6 +836,7 @@ typedef struct _SnortConfig
      * rules, or any combination. We process the uricontent 1st,
      * then the content, and then the no content rules for udp/tcp
      * and icmp, than we process the ip rules. */
+    PORT_RULE_MAP *prmEthRTNX;
     PORT_RULE_MAP *prmIpRTNX;
     PORT_RULE_MAP *prmTcpRTNX;
     PORT_RULE_MAP *prmUdpRTNX;



------------------------------------------------------------------------------
Write once. Port to many.
Get the SDK and tools to simplify cross-platform app development. Create 
new or port existing apps to sell to consumers worldwide. Explore the 
Intel AppUpSM program developer opportunity. appdeveloper.intel.com/join
http://p.sf.net/sfu/intel-appdev

_______________________________________________
Snort-devel mailing list
Snort-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/snort-devel

Please visit http://blog.snort.org for the latest news about Snort!

[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic