Commit 1bca1320 authored by Bart De Schuymer's avatar Bart De Schuymer Committed by David S. Miller

[BRIDGE]: Deal with non-linear SKBs in ebtables.

parent 7768d03b
...@@ -34,7 +34,7 @@ static inline int should_deliver(const struct net_bridge_port *p, ...@@ -34,7 +34,7 @@ static inline int should_deliver(const struct net_bridge_port *p,
int br_dev_queue_push_xmit(struct sk_buff *skb) int br_dev_queue_push_xmit(struct sk_buff *skb)
{ {
#ifdef CONFIG_NETFILTER #ifdef CONFIG_NETFILTER
/* FIXME: skb bas not been linearized: is this valid?? --RR */ /* ip_refrag calls ip_fragment, which doesn't copy the MAC header. */
if (skb->nf_bridge) if (skb->nf_bridge)
memcpy(skb->data - 16, skb->nf_bridge->hh, 16); memcpy(skb->data - 16, skb->nf_bridge->hh, 16);
#endif #endif
......
...@@ -468,8 +468,7 @@ static unsigned int br_nf_post_routing(unsigned int hook, struct sk_buff **pskb, ...@@ -468,8 +468,7 @@ static unsigned int br_nf_post_routing(unsigned int hook, struct sk_buff **pskb,
struct sk_buff *skb = *pskb; struct sk_buff *skb = *pskb;
struct nf_bridge_info *nf_bridge = (*pskb)->nf_bridge; struct nf_bridge_info *nf_bridge = (*pskb)->nf_bridge;
/* FIXME: skb as not been linearized. Is this still true? --RR */ /* Be very paranoid. Must be a device driver bug. */
/* Be very paranoid. */
if (skb->mac.raw < skb->head || skb->mac.raw + ETH_HLEN > skb->data) { if (skb->mac.raw < skb->head || skb->mac.raw + ETH_HLEN > skb->data) {
printk(KERN_CRIT "br_netfilter: Argh!! br_nf_post_routing: " printk(KERN_CRIT "br_netfilter: Argh!! br_nf_post_routing: "
"bad mac.raw pointer."); "bad mac.raw pointer.");
......
...@@ -19,89 +19,72 @@ static int ebt_filter_arp(const struct sk_buff *skb, const struct net_device *in ...@@ -19,89 +19,72 @@ static int ebt_filter_arp(const struct sk_buff *skb, const struct net_device *in
const struct net_device *out, const void *data, unsigned int datalen) const struct net_device *out, const void *data, unsigned int datalen)
{ {
struct ebt_arp_info *info = (struct ebt_arp_info *)data; struct ebt_arp_info *info = (struct ebt_arp_info *)data;
struct arphdr arph;
if (skb_copy_bits(skb, 0, &arph, sizeof(arph)))
return EBT_NOMATCH;
if (info->bitmask & EBT_ARP_OPCODE && FWINV(info->opcode != if (info->bitmask & EBT_ARP_OPCODE && FWINV(info->opcode !=
((*skb).nh.arph)->ar_op, EBT_ARP_OPCODE)) arph.ar_op, EBT_ARP_OPCODE))
return EBT_NOMATCH; return EBT_NOMATCH;
if (info->bitmask & EBT_ARP_HTYPE && FWINV(info->htype != if (info->bitmask & EBT_ARP_HTYPE && FWINV(info->htype !=
((*skb).nh.arph)->ar_hrd, EBT_ARP_HTYPE)) arph.ar_hrd, EBT_ARP_HTYPE))
return EBT_NOMATCH; return EBT_NOMATCH;
if (info->bitmask & EBT_ARP_PTYPE && FWINV(info->ptype != if (info->bitmask & EBT_ARP_PTYPE && FWINV(info->ptype !=
((*skb).nh.arph)->ar_pro, EBT_ARP_PTYPE)) arph.ar_pro, EBT_ARP_PTYPE))
return EBT_NOMATCH; return EBT_NOMATCH;
if (info->bitmask & (EBT_ARP_SRC_IP | EBT_ARP_DST_IP)) if (info->bitmask & (EBT_ARP_SRC_IP | EBT_ARP_DST_IP)) {
{ uint32_t addr;
uint32_t arp_len = sizeof(struct arphdr) +
(2 * (((*skb).nh.arph)->ar_hln)) +
(2 * (((*skb).nh.arph)->ar_pln));
uint32_t dst;
uint32_t src;
/* Make sure the packet is long enough */
if ((((*skb).nh.raw) + arp_len) > (*skb).tail)
return EBT_NOMATCH;
/* IPv4 addresses are always 4 bytes */ /* IPv4 addresses are always 4 bytes */
if (((*skb).nh.arph)->ar_pln != sizeof(uint32_t)) if (arph.ar_pln != sizeof(uint32_t))
return EBT_NOMATCH; return EBT_NOMATCH;
if (info->bitmask & EBT_ARP_SRC_IP) { if (info->bitmask & EBT_ARP_SRC_IP) {
memcpy(&src, ((*skb).nh.raw) + sizeof(struct arphdr) + if (skb_copy_bits(skb, sizeof(struct arphdr) +
((*skb).nh.arph)->ar_hln, sizeof(uint32_t)); arph.ar_hln, &addr, sizeof(addr)))
if (FWINV(info->saddr != (src & info->smsk), return EBT_NOMATCH;
if (FWINV(info->saddr != (addr & info->smsk),
EBT_ARP_SRC_IP)) EBT_ARP_SRC_IP))
return EBT_NOMATCH; return EBT_NOMATCH;
} }
if (info->bitmask & EBT_ARP_DST_IP) { if (info->bitmask & EBT_ARP_DST_IP) {
memcpy(&dst, ((*skb).nh.raw)+sizeof(struct arphdr) + if (skb_copy_bits(skb, sizeof(struct arphdr) +
(2*(((*skb).nh.arph)->ar_hln)) + 2*arph.ar_hln + sizeof(uint32_t), &addr,
(((*skb).nh.arph)->ar_pln), sizeof(uint32_t)); sizeof(addr)))
if (FWINV(info->daddr != (dst & info->dmsk), return EBT_NOMATCH;
if (FWINV(info->daddr != (addr & info->dmsk),
EBT_ARP_DST_IP)) EBT_ARP_DST_IP))
return EBT_NOMATCH; return EBT_NOMATCH;
} }
} }
if (info->bitmask & (EBT_ARP_SRC_MAC | EBT_ARP_DST_MAC)) if (info->bitmask & (EBT_ARP_SRC_MAC | EBT_ARP_DST_MAC)) {
{ unsigned char mac[ETH_ALEN];
uint32_t arp_len = sizeof(struct arphdr) + uint8_t verdict, i;
(2 * (((*skb).nh.arph)->ar_hln)) +
(2 * (((*skb).nh.arph)->ar_pln));
unsigned char dst[ETH_ALEN];
unsigned char src[ETH_ALEN];
/* Make sure the packet is long enough */
if ((((*skb).nh.raw) + arp_len) > (*skb).tail)
return EBT_NOMATCH;
/* MAC addresses are 6 bytes */ /* MAC addresses are 6 bytes */
if (((*skb).nh.arph)->ar_hln != ETH_ALEN) if (arph.ar_hln != ETH_ALEN)
return EBT_NOMATCH; return EBT_NOMATCH;
if (info->bitmask & EBT_ARP_SRC_MAC) { if (info->bitmask & EBT_ARP_SRC_MAC) {
uint8_t verdict, i; if (skb_copy_bits(skb, sizeof(struct arphdr), &mac,
ETH_ALEN))
memcpy(&src, ((*skb).nh.raw) + return EBT_NOMATCH;
sizeof(struct arphdr),
ETH_ALEN);
verdict = 0; verdict = 0;
for (i = 0; i < 6; i++) for (i = 0; i < 6; i++)
verdict |= (src[i] ^ info->smaddr[i]) & verdict |= (mac[i] ^ info->smaddr[i]) &
info->smmsk[i]; info->smmsk[i];
if (FWINV(verdict != 0, EBT_ARP_SRC_MAC)) if (FWINV(verdict != 0, EBT_ARP_SRC_MAC))
return EBT_NOMATCH; return EBT_NOMATCH;
} }
if (info->bitmask & EBT_ARP_DST_MAC) { if (info->bitmask & EBT_ARP_DST_MAC) {
uint8_t verdict, i; if (skb_copy_bits(skb, sizeof(struct arphdr) +
arph.ar_hln + arph.ar_pln, &mac, ETH_ALEN))
memcpy(&dst, ((*skb).nh.raw) + return EBT_NOMATCH;
sizeof(struct arphdr) +
(((*skb).nh.arph)->ar_hln) +
(((*skb).nh.arph)->ar_pln),
ETH_ALEN);
verdict = 0; verdict = 0;
for (i = 0; i < 6; i++) for (i = 0; i < 6; i++)
verdict |= (dst[i] ^ info->dmaddr[i]) & verdict |= (mac[i] ^ info->dmaddr[i]) &
info->dmmsk[i]; info->dmmsk[i];
if (FWINV(verdict != 0, EBT_ARP_DST_MAC)) if (FWINV(verdict != 0, EBT_ARP_DST_MAC))
return EBT_NOMATCH; return EBT_NOMATCH;
......
...@@ -23,53 +23,50 @@ struct tcpudphdr { ...@@ -23,53 +23,50 @@ struct tcpudphdr {
uint16_t dst; uint16_t dst;
}; };
union h_u {
unsigned char *raw;
struct tcpudphdr *tuh;
};
static int ebt_filter_ip(const struct sk_buff *skb, const struct net_device *in, static int ebt_filter_ip(const struct sk_buff *skb, const struct net_device *in,
const struct net_device *out, const void *data, const struct net_device *out, const void *data,
unsigned int datalen) unsigned int datalen)
{ {
struct ebt_ip_info *info = (struct ebt_ip_info *)data; struct ebt_ip_info *info = (struct ebt_ip_info *)data;
union {struct iphdr iph; struct tcpudphdr ports;} u;
if (skb_copy_bits(skb, 0, &u.iph, sizeof(u.iph)))
return EBT_NOMATCH;
if (info->bitmask & EBT_IP_TOS && if (info->bitmask & EBT_IP_TOS &&
FWINV(info->tos != ((*skb).nh.iph)->tos, EBT_IP_TOS)) FWINV(info->tos != u.iph.tos, EBT_IP_TOS))
return EBT_NOMATCH; return EBT_NOMATCH;
if (info->bitmask & EBT_IP_PROTO) {
if (FWINV(info->protocol != ((*skb).nh.iph)->protocol,
EBT_IP_PROTO))
return EBT_NOMATCH;
if ( info->protocol == IPPROTO_TCP ||
info->protocol == IPPROTO_UDP )
{
union h_u h;
h.raw = skb->data + skb->nh.iph->ihl*4;
if (info->bitmask & EBT_IP_DPORT) {
uint16_t port = ntohs(h.tuh->dst);
if (FWINV(port < info->dport[0] ||
port > info->dport[1],
EBT_IP_DPORT))
return EBT_NOMATCH;
}
if (info->bitmask & EBT_IP_SPORT) {
uint16_t port = ntohs(h.tuh->src);
if (FWINV(port < info->sport[0] ||
port > info->sport[1],
EBT_IP_SPORT))
return EBT_NOMATCH;
}
}
}
if (info->bitmask & EBT_IP_SOURCE && if (info->bitmask & EBT_IP_SOURCE &&
FWINV((((*skb).nh.iph)->saddr & info->smsk) != FWINV((u.iph.saddr & info->smsk) !=
info->saddr, EBT_IP_SOURCE)) info->saddr, EBT_IP_SOURCE))
return EBT_NOMATCH; return EBT_NOMATCH;
if ((info->bitmask & EBT_IP_DEST) && if ((info->bitmask & EBT_IP_DEST) &&
FWINV((((*skb).nh.iph)->daddr & info->dmsk) != FWINV((u.iph.daddr & info->dmsk) !=
info->daddr, EBT_IP_DEST)) info->daddr, EBT_IP_DEST))
return EBT_NOMATCH; return EBT_NOMATCH;
if (info->bitmask & EBT_IP_PROTO) {
if (FWINV(info->protocol != u.iph.protocol, EBT_IP_PROTO))
return EBT_NOMATCH;
if (!(info->bitmask & EBT_IP_DPORT) &&
!(info->bitmask & EBT_IP_SPORT))
return EBT_MATCH;
if (skb_copy_bits(skb, u.iph.ihl*4, &u.ports,
sizeof(u.ports)))
return EBT_NOMATCH;
if (info->bitmask & EBT_IP_DPORT) {
u.ports.dst = ntohs(u.ports.dst);
if (FWINV(u.ports.dst < info->dport[0] ||
u.ports.dst > info->dport[1],
EBT_IP_DPORT))
return EBT_NOMATCH;
}
if (info->bitmask & EBT_IP_SPORT) {
u.ports.src = ntohs(u.ports.src);
if (FWINV(u.ports.src < info->sport[0] ||
u.ports.src > info->sport[1],
EBT_IP_SPORT))
return EBT_NOMATCH;
}
}
return EBT_MATCH; return EBT_MATCH;
} }
...@@ -86,7 +83,7 @@ static int ebt_ip_check(const char *tablename, unsigned int hookmask, ...@@ -86,7 +83,7 @@ static int ebt_ip_check(const char *tablename, unsigned int hookmask,
if (info->bitmask & ~EBT_IP_MASK || info->invflags & ~EBT_IP_MASK) if (info->bitmask & ~EBT_IP_MASK || info->invflags & ~EBT_IP_MASK)
return -EINVAL; return -EINVAL;
if (info->bitmask & (EBT_IP_DPORT | EBT_IP_SPORT)) { if (info->bitmask & (EBT_IP_DPORT | EBT_IP_SPORT)) {
if (info->bitmask & EBT_IPROTO) if (info->invflags & EBT_IP_PROTO)
return -EINVAL; return -EINVAL;
if (info->protocol != IPPROTO_TCP && if (info->protocol != IPPROTO_TCP &&
info->protocol != IPPROTO_UDP) info->protocol != IPPROTO_UDP)
......
...@@ -32,48 +32,105 @@ static int ebt_log_check(const char *tablename, unsigned int hookmask, ...@@ -32,48 +32,105 @@ static int ebt_log_check(const char *tablename, unsigned int hookmask,
return 0; return 0;
} }
struct tcpudphdr
{
uint16_t src;
uint16_t dst;
};
struct arppayload
{
unsigned char mac_src[ETH_ALEN];
unsigned char ip_src[4];
unsigned char mac_dst[ETH_ALEN];
unsigned char ip_dst[4];
};
static void print_MAC(unsigned char *p)
{
int i;
for (i = 0; i < ETH_ALEN; i++, p++)
printk("%02x%c", *p, i == ETH_ALEN - 1 ? ' ':':');
}
#define myNIPQUAD(a) a[0], a[1], a[2], a[3]
static void ebt_log(const struct sk_buff *skb, const struct net_device *in, static void ebt_log(const struct sk_buff *skb, const struct net_device *in,
const struct net_device *out, const void *data, unsigned int datalen) const struct net_device *out, const void *data, unsigned int datalen)
{ {
struct ebt_log_info *info = (struct ebt_log_info *)data; struct ebt_log_info *info = (struct ebt_log_info *)data;
char level_string[4] = "< >"; char level_string[4] = "< >";
level_string[1] = '0' + info->loglevel; union {struct iphdr iph; struct tcpudphdr ports;
struct arphdr arph; struct arppayload arpp;} u;
level_string[1] = '0' + info->loglevel;
spin_lock_bh(&ebt_log_lock); spin_lock_bh(&ebt_log_lock);
printk(level_string); printk(level_string);
printk("%s IN=%s OUT=%s ", info->prefix, in ? in->name : "", printk("%s IN=%s OUT=%s ", info->prefix, in ? in->name : "",
out ? out->name : ""); out ? out->name : "");
if (skb->dev->hard_header_len) { printk("MAC source = ");
int i; print_MAC((skb->mac.ethernet)->h_source);
unsigned char *p = (skb->mac.ethernet)->h_source; printk("MAC dest = ");
print_MAC((skb->mac.ethernet)->h_dest);
printk("MAC source = ");
for (i = 0; i < ETH_ALEN; i++,p++)
printk("%02x%c", *p, i == ETH_ALEN - 1 ? ' ':':');
printk("MAC dest = ");
p = (skb->mac.ethernet)->h_dest;
for (i = 0; i < ETH_ALEN; i++,p++)
printk("%02x%c", *p, i == ETH_ALEN - 1 ? ' ':':');
}
printk("proto = 0x%04x", ntohs(((*skb).mac.ethernet)->h_proto)); printk("proto = 0x%04x", ntohs(((*skb).mac.ethernet)->h_proto));
if ((info->bitmask & EBT_LOG_IP) && skb->mac.ethernet->h_proto == if ((info->bitmask & EBT_LOG_IP) && skb->mac.ethernet->h_proto ==
htons(ETH_P_IP)){ htons(ETH_P_IP)){
struct iphdr *iph = skb->nh.iph; if (skb_copy_bits(skb, 0, &u.iph, sizeof(u.iph))) {
printk(" INCOMPLETE IP header");
goto out;
}
printk(" IP SRC=%u.%u.%u.%u IP DST=%u.%u.%u.%u,", printk(" IP SRC=%u.%u.%u.%u IP DST=%u.%u.%u.%u,",
NIPQUAD(iph->saddr), NIPQUAD(iph->daddr)); NIPQUAD(u.iph.saddr), NIPQUAD(u.iph.daddr));
printk(" IP tos=0x%02X, IP proto=%d", iph->tos, iph->protocol); printk(" IP tos=0x%02X, IP proto=%d", u.iph.tos,
u.iph.protocol);
if (u.iph.protocol == IPPROTO_TCP ||
u.iph.protocol == IPPROTO_UDP) {
if (skb_copy_bits(skb, u.iph.ihl*4, &u.ports,
sizeof(u.ports))) {
printk(" INCOMPLETE TCP/UDP header");
goto out;
}
printk(" SPT=%u DPT=%u", ntohs(u.ports.src),
ntohs(u.ports.dst));
}
goto out;
} }
if ((info->bitmask & EBT_LOG_ARP) && if ((info->bitmask & EBT_LOG_ARP) &&
((skb->mac.ethernet->h_proto == __constant_htons(ETH_P_ARP)) || ((skb->mac.ethernet->h_proto == __constant_htons(ETH_P_ARP)) ||
(skb->mac.ethernet->h_proto == __constant_htons(ETH_P_RARP)))) { (skb->mac.ethernet->h_proto == __constant_htons(ETH_P_RARP)))) {
struct arphdr * arph = skb->nh.arph; if (skb_copy_bits(skb, 0, &u.arph, sizeof(u.arph))) {
printk(" INCOMPLETE ARP header");
goto out;
}
printk(" ARP HTYPE=%d, PTYPE=0x%04x, OPCODE=%d", printk(" ARP HTYPE=%d, PTYPE=0x%04x, OPCODE=%d",
ntohs(arph->ar_hrd), ntohs(arph->ar_pro), ntohs(u.arph.ar_hrd), ntohs(u.arph.ar_pro),
ntohs(arph->ar_op)); ntohs(u.arph.ar_op));
/* If it's for Ethernet and the lengths are OK,
* then log the ARP payload */
if (u.arph.ar_hrd == __constant_htons(1) &&
u.arph.ar_hln == ETH_ALEN &&
u.arph.ar_pln == sizeof(uint32_t)) {
if (skb_copy_bits(skb, sizeof(u.arph), &u.arpp,
sizeof(u.arpp))) {
printk(" INCOMPLETE ARP payload");
goto out;
}
printk(" ARP MAC SRC=");
print_MAC(u.arpp.mac_src);
printk(" ARP IP SRC=%u.%u.%u.%u",
myNIPQUAD(u.arpp.ip_src));
printk(" ARP MAC DST=");
print_MAC(u.arpp.mac_dst);
printk(" ARP IP DST=%u.%u.%u.%u",
myNIPQUAD(u.arpp.ip_dst));
}
} }
out:
printk("\n"); printk("\n");
spin_unlock_bh(&ebt_log_lock); spin_unlock_bh(&ebt_log_lock);
} }
......
...@@ -2,17 +2,17 @@ ...@@ -2,17 +2,17 @@
* Description: EBTables 802.1Q match extension kernelspace module. * Description: EBTables 802.1Q match extension kernelspace module.
* Authors: Nick Fedchik <nick@fedchik.org.ua> * Authors: Nick Fedchik <nick@fedchik.org.ua>
* Bart De Schuymer <bdschuym@pandora.be> * Bart De Schuymer <bdschuym@pandora.be>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or * the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
...@@ -39,92 +39,53 @@ MODULE_LICENSE("GPL"); ...@@ -39,92 +39,53 @@ MODULE_LICENSE("GPL");
#define INV_FLAG(_inv_flag_) (info->invflags & _inv_flag_) ? "!" : "" #define INV_FLAG(_inv_flag_) (info->invflags & _inv_flag_) ? "!" : ""
#define GET_BITMASK(_BIT_MASK_) info->bitmask & _BIT_MASK_ #define GET_BITMASK(_BIT_MASK_) info->bitmask & _BIT_MASK_
#define SET_BITMASK(_BIT_MASK_) info->bitmask |= _BIT_MASK_ #define SET_BITMASK(_BIT_MASK_) info->bitmask |= _BIT_MASK_
#define EXIT_ON_MISMATCH(_MATCH_,_MASK_) if (!((info->_MATCH_ == _MATCH_)^!!(info->invflags & _MASK_))) return 1; #define EXIT_ON_MISMATCH(_MATCH_,_MASK_) {if (!((info->_MATCH_ == _MATCH_)^!!(info->invflags & _MASK_))) return EBT_NOMATCH;}
/*
* Function description: ebt_filter_vlan() is main engine for
* checking passed 802.1Q frame according to
* the passed extension parameters (in the *data buffer)
* ebt_filter_vlan() is called after successful check the rule params
* by ebt_check_vlan() function.
* Parameters:
* const struct sk_buff *skb - pointer to passed ethernet frame buffer
* const void *data - pointer to passed extension parameters
* unsigned int datalen - length of passed *data buffer
* const struct net_device *in -
* const struct net_device *out -
* const struct ebt_counter *c -
* Returned values:
* 0 - ok (all rule params matched)
* 1 - miss (rule params not acceptable to the parsed frame)
*/
static int static int
ebt_filter_vlan(const struct sk_buff *skb, ebt_filter_vlan(const struct sk_buff *skb,
const struct net_device *in, const struct net_device *in,
const struct net_device *out, const struct net_device *out,
const void *data, unsigned int datalen) const void *data, unsigned int datalen)
{ {
struct ebt_vlan_info *info = (struct ebt_vlan_info *) data; /* userspace data */ struct ebt_vlan_info *info = (struct ebt_vlan_info *) data;
struct vlan_ethhdr *frame = (struct vlan_ethhdr *) skb->mac.raw; /* Passed tagged frame */ struct vlan_ethhdr frame;
unsigned short TCI; /* Whole TCI, given from parsed frame */ unsigned short TCI; /* Whole TCI, given from parsed frame */
unsigned short id; /* VLAN ID, given from frame TCI */ unsigned short id; /* VLAN ID, given from frame TCI */
unsigned char prio; /* user_priority, given from frame TCI */ unsigned char prio; /* user_priority, given from frame TCI */
unsigned short encap; /* VLAN encapsulated Type/Length field, given from orig frame */ /* VLAN encapsulated Type/Length field, given from orig frame */
unsigned short encap;
/* if (skb_copy_bits(skb, 0, &frame, sizeof(frame)))
* Tag Control Information (TCI) consists of the following elements: return EBT_NOMATCH;
* - User_priority. The user_priority field is three bits in length,
* interpreted as a binary number. /* Tag Control Information (TCI) consists of the following elements:
* - Canonical Format Indicator (CFI). The Canonical Format Indicator * - User_priority. The user_priority field is three bits in length,
* interpreted as a binary number.
* - Canonical Format Indicator (CFI). The Canonical Format Indicator
* (CFI) is a single bit flag value. Currently ignored. * (CFI) is a single bit flag value. Currently ignored.
* - VLAN Identifier (VID). The VID is encoded as * - VLAN Identifier (VID). The VID is encoded as
* an unsigned binary number. * an unsigned binary number. */
*/ TCI = ntohs(frame.h_vlan_TCI);
TCI = ntohs(frame->h_vlan_TCI);
id = TCI & VLAN_VID_MASK; id = TCI & VLAN_VID_MASK;
prio = (TCI >> 13) & 0x7; prio = (TCI >> 13) & 0x7;
encap = frame->h_vlan_encapsulated_proto; encap = frame.h_vlan_encapsulated_proto;
/* /* Checking VLAN Identifier (VID) */
* Checking VLAN Identifier (VID) if (GET_BITMASK(EBT_VLAN_ID))
*/
if (GET_BITMASK(EBT_VLAN_ID)) { /* Is VLAN ID parsed? */
EXIT_ON_MISMATCH(id, EBT_VLAN_ID); EXIT_ON_MISMATCH(id, EBT_VLAN_ID);
}
/* /* Checking user_priority */
* Checking user_priority if (GET_BITMASK(EBT_VLAN_PRIO))
*/
if (GET_BITMASK(EBT_VLAN_PRIO)) { /* Is VLAN user_priority parsed? */
EXIT_ON_MISMATCH(prio, EBT_VLAN_PRIO); EXIT_ON_MISMATCH(prio, EBT_VLAN_PRIO);
}
/* /* Checking Encapsulated Proto (Length/Type) field */
* Checking Encapsulated Proto (Length/Type) field if (GET_BITMASK(EBT_VLAN_ENCAP))
*/
if (GET_BITMASK(EBT_VLAN_ENCAP)) { /* Is VLAN Encap parsed? */
EXIT_ON_MISMATCH(encap, EBT_VLAN_ENCAP); EXIT_ON_MISMATCH(encap, EBT_VLAN_ENCAP);
}
/* return EBT_MATCH;
* All possible extension parameters was parsed.
* If rule never returned by missmatch, then all ok.
*/
return 0;
} }
/*
* Function description: ebt_vlan_check() is called when userspace
* delivers the table entry to the kernel,
* and to check that userspace doesn't give a bad table.
* Parameters:
* const char *tablename - table name string
* unsigned int hooknr - hook number
* const struct ebt_entry *e - ebtables entry basic set
* const void *data - pointer to passed extension parameters
* unsigned int datalen - length of passed *data buffer
* Returned values:
* 0 - ok (all delivered rule params are correct)
* 1 - miss (rule params is out of range, invalid, incompatible, etc.)
*/
static int static int
ebt_check_vlan(const char *tablename, ebt_check_vlan(const char *tablename,
unsigned int hooknr, unsigned int hooknr,
...@@ -132,9 +93,7 @@ ebt_check_vlan(const char *tablename, ...@@ -132,9 +93,7 @@ ebt_check_vlan(const char *tablename,
{ {
struct ebt_vlan_info *info = (struct ebt_vlan_info *) data; struct ebt_vlan_info *info = (struct ebt_vlan_info *) data;
/* /* Parameters buffer overflow check */
* Parameters buffer overflow check
*/
if (datalen != sizeof(struct ebt_vlan_info)) { if (datalen != sizeof(struct ebt_vlan_info)) {
DEBUG_MSG DEBUG_MSG
("passed size %d is not eq to ebt_vlan_info (%Zd)\n", ("passed size %d is not eq to ebt_vlan_info (%Zd)\n",
...@@ -142,9 +101,7 @@ ebt_check_vlan(const char *tablename, ...@@ -142,9 +101,7 @@ ebt_check_vlan(const char *tablename,
return -EINVAL; return -EINVAL;
} }
/* /* Is it 802.1Q frame checked? */
* Is it 802.1Q frame checked?
*/
if (e->ethproto != __constant_htons(ETH_P_8021Q)) { if (e->ethproto != __constant_htons(ETH_P_8021Q)) {
DEBUG_MSG DEBUG_MSG
("passed entry proto %2.4X is not 802.1Q (8100)\n", ("passed entry proto %2.4X is not 802.1Q (8100)\n",
...@@ -152,67 +109,54 @@ ebt_check_vlan(const char *tablename, ...@@ -152,67 +109,54 @@ ebt_check_vlan(const char *tablename,
return -EINVAL; return -EINVAL;
} }
/* /* Check for bitmask range
* Check for bitmask range * True if even one bit is out of mask */
* True if even one bit is out of mask
*/
if (info->bitmask & ~EBT_VLAN_MASK) { if (info->bitmask & ~EBT_VLAN_MASK) {
DEBUG_MSG("bitmask %2X is out of mask (%2X)\n", DEBUG_MSG("bitmask %2X is out of mask (%2X)\n",
info->bitmask, EBT_VLAN_MASK); info->bitmask, EBT_VLAN_MASK);
return -EINVAL; return -EINVAL;
} }
/* /* Check for inversion flags range */
* Check for inversion flags range
*/
if (info->invflags & ~EBT_VLAN_MASK) { if (info->invflags & ~EBT_VLAN_MASK) {
DEBUG_MSG("inversion flags %2X is out of mask (%2X)\n", DEBUG_MSG("inversion flags %2X is out of mask (%2X)\n",
info->invflags, EBT_VLAN_MASK); info->invflags, EBT_VLAN_MASK);
return -EINVAL; return -EINVAL;
} }
/* /* Reserved VLAN ID (VID) values
* Reserved VLAN ID (VID) values
* ----------------------------- * -----------------------------
* 0 - The null VLAN ID. * 0 - The null VLAN ID.
* 1 - The default Port VID (PVID) * 1 - The default Port VID (PVID)
* 0x0FFF - Reserved for implementation use. * 0x0FFF - Reserved for implementation use.
* if_vlan.h: VLAN_GROUP_ARRAY_LEN 4096. * if_vlan.h: VLAN_GROUP_ARRAY_LEN 4096. */
*/ if (GET_BITMASK(EBT_VLAN_ID)) {
if (GET_BITMASK(EBT_VLAN_ID)) { /* when vlan-id param was spec-ed */ if (!!info->id) { /* if id!=0 => check vid range */
if (!!info->id) { /* if id!=0 => check vid range */
if (info->id > VLAN_GROUP_ARRAY_LEN) { if (info->id > VLAN_GROUP_ARRAY_LEN) {
DEBUG_MSG DEBUG_MSG
("id %d is out of range (1-4096)\n", ("id %d is out of range (1-4096)\n",
info->id); info->id);
return -EINVAL; return -EINVAL;
} }
/* /* Note: This is valid VLAN-tagged frame point.
* Note: This is valid VLAN-tagged frame point.
* Any value of user_priority are acceptable, * Any value of user_priority are acceptable,
* but should be ignored according to 802.1Q Std. * but should be ignored according to 802.1Q Std.
* So we just drop the prio flag. * So we just drop the prio flag. */
*/
info->bitmask &= ~EBT_VLAN_PRIO; info->bitmask &= ~EBT_VLAN_PRIO;
} }
/* /* Else, id=0 (null VLAN ID) => user_priority range (any?) */
* Else, id=0 (null VLAN ID) => user_priority range (any?)
*/
} }
if (GET_BITMASK(EBT_VLAN_PRIO)) { if (GET_BITMASK(EBT_VLAN_PRIO)) {
if ((unsigned char) info->prio > 7) { if ((unsigned char) info->prio > 7) {
DEBUG_MSG DEBUG_MSG("prio %d is out of range (0-7)\n",
("prio %d is out of range (0-7)\n",
info->prio); info->prio);
return -EINVAL; return -EINVAL;
} }
} }
/* /* Check for encapsulated proto range - it is possible to be
* Check for encapsulated proto range - it is possible to be
* any value for u_short range. * any value for u_short range.
* if_ether.h: ETH_ZLEN 60 - Min. octets in frame sans FCS * if_ether.h: ETH_ZLEN 60 - Min. octets in frame sans FCS */
*/
if (GET_BITMASK(EBT_VLAN_ENCAP)) { if (GET_BITMASK(EBT_VLAN_ENCAP)) {
if ((unsigned short) ntohs(info->encap) < ETH_ZLEN) { if ((unsigned short) ntohs(info->encap) < ETH_ZLEN) {
DEBUG_MSG DEBUG_MSG
...@@ -232,9 +176,6 @@ static struct ebt_match filter_vlan = { ...@@ -232,9 +176,6 @@ static struct ebt_match filter_vlan = {
.me = THIS_MODULE, .me = THIS_MODULE,
}; };
/*
* Module initialization function.
*/
static int __init init(void) static int __init init(void)
{ {
DEBUG_MSG("ebtables 802.1Q extension module v" DEBUG_MSG("ebtables 802.1Q extension module v"
...@@ -243,9 +184,6 @@ static int __init init(void) ...@@ -243,9 +184,6 @@ static int __init init(void)
return ebt_register_match(&filter_vlan); return ebt_register_match(&filter_vlan);
} }
/*
* Module "finalization" function
*/
static void __exit fini(void) static void __exit fini(void)
{ {
ebt_unregister_match(&filter_vlan); ebt_unregister_match(&filter_vlan);
......
...@@ -175,10 +175,6 @@ unsigned int ebt_do_table (unsigned int hook, struct sk_buff **pskb, ...@@ -175,10 +175,6 @@ unsigned int ebt_do_table (unsigned int hook, struct sk_buff **pskb,
char *base; char *base;
struct ebt_table_info *private = table->private; struct ebt_table_info *private = table->private;
/* FIXME: Push down to extensions --RR */
if (skb_is_nonlinear(*pskb) && skb_linearize(*pskb, GFP_ATOMIC) != 0)
return NF_DROP;
read_lock_bh(&table->lock); read_lock_bh(&table->lock);
cb_base = COUNTER_BASE(private->counters, private->nentries, cb_base = COUNTER_BASE(private->counters, private->nentries,
smp_processor_id()); smp_processor_id());
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment