Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 352444
b: refs/heads/master
c: 7885198
h: refs/heads/master
v: v3
  • Loading branch information
Vlad Yasevich authored and David S. Miller committed Feb 14, 2013
1 parent 3743319 commit b5479ec
Show file tree
Hide file tree
Showing 7 changed files with 127 additions and 11 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 6cbdceeb1cb12c7d620161925a8c3e81daadb2e4
refs/heads/master: 7885198861fc9a3dfdc6bb90dc0ba12689d6cd57
1 change: 1 addition & 0 deletions trunk/net/8021q/vlan_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ struct sk_buff *vlan_untag(struct sk_buff *skb)
kfree_skb(skb);
return NULL;
}
EXPORT_SYMBOL(vlan_untag);


/*
Expand Down
3 changes: 2 additions & 1 deletion trunk/net/bridge/br_device.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev)
struct net_bridge_fdb_entry *dst;
struct net_bridge_mdb_entry *mdst;
struct br_cpu_netstats *brstats = this_cpu_ptr(br->stats);
u16 vid = 0;

rcu_read_lock();
#ifdef CONFIG_BRIDGE_NETFILTER
Expand All @@ -45,7 +46,7 @@ netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev)
brstats->tx_bytes += skb->len;
u64_stats_update_end(&brstats->syncp);

if (!br_allowed_ingress(br, br_get_vlan_info(br), skb))
if (!br_allowed_ingress(br, br_get_vlan_info(br), skb, &vid))
goto out;

BR_INPUT_SKB_CB(skb)->brdev = dev;
Expand Down
8 changes: 8 additions & 0 deletions trunk/net/bridge/br_forward.c
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,10 @@ int br_forward_finish(struct sk_buff *skb)

static void __br_deliver(const struct net_bridge_port *to, struct sk_buff *skb)
{
skb = br_handle_vlan(to->br, nbp_get_vlan_info(to), skb);
if (!skb)
return;

skb->dev = to->dev;

if (unlikely(netpoll_tx_running(to->br->dev))) {
Expand All @@ -89,6 +93,10 @@ static void __br_forward(const struct net_bridge_port *to, struct sk_buff *skb)
return;
}

skb = br_handle_vlan(to->br, nbp_get_vlan_info(to), skb);
if (!skb)
return;

indev = skb->dev;
skb->dev = to->dev;
skb_forward_csum(skb);
Expand Down
7 changes: 6 additions & 1 deletion trunk/net/bridge/br_input.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ static int br_pass_frame_up(struct sk_buff *skb)
return NET_RX_DROP;
}

skb = br_handle_vlan(br, br_get_vlan_info(br), skb);
if (!skb)
return NET_RX_DROP;

indev = skb->dev;
skb->dev = brdev;

Expand All @@ -61,11 +65,12 @@ int br_handle_frame_finish(struct sk_buff *skb)
struct net_bridge_fdb_entry *dst;
struct net_bridge_mdb_entry *mdst;
struct sk_buff *skb2;
u16 vid = 0;

if (!p || p->state == BR_STATE_DISABLED)
goto drop;

if (!br_allowed_ingress(p->br, nbp_get_vlan_info(p), skb))
if (!br_allowed_ingress(p->br, nbp_get_vlan_info(p), skb, &vid))
goto drop;

/* insert into forwarding database after filtering to avoid spoofing */
Expand Down
34 changes: 31 additions & 3 deletions trunk/net/bridge/br_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ struct br_ip

struct net_port_vlans {
u16 port_idx;
u16 pvid;
union {
struct net_bridge_port *port;
struct net_bridge *br;
Expand Down Expand Up @@ -554,10 +555,13 @@ static inline void br_mdb_uninit(void)
/* br_vlan.c */
#ifdef CONFIG_BRIDGE_VLAN_FILTERING
extern bool br_allowed_ingress(struct net_bridge *br, struct net_port_vlans *v,
struct sk_buff *skb);
struct sk_buff *skb, u16 *vid);
extern bool br_allowed_egress(struct net_bridge *br,
const struct net_port_vlans *v,
const struct sk_buff *skb);
extern struct sk_buff *br_handle_vlan(struct net_bridge *br,
const struct net_port_vlans *v,
struct sk_buff *skb);
extern int br_vlan_add(struct net_bridge *br, u16 vid);
extern int br_vlan_delete(struct net_bridge *br, u16 vid);
extern void br_vlan_flush(struct net_bridge *br);
Expand Down Expand Up @@ -594,10 +598,23 @@ static inline int br_vlan_get_tag(const struct sk_buff *skb, u16 *vid)

return err;
}

static inline u16 br_get_pvid(const struct net_port_vlans *v)
{
/* Return just the VID if it is set, or VLAN_N_VID (invalid vid) if
* vid wasn't set
*/
smp_rmb();
return (v->pvid & VLAN_TAG_PRESENT) ?
(v->pvid & ~VLAN_TAG_PRESENT) :
VLAN_N_VID;
}

#else
static inline bool br_allowed_ingress(struct net_bridge *br,
struct net_port_vlans *v,
struct sk_buff *skb)
struct sk_buff *skb,
u16 *vid)
{
return true;
}
Expand All @@ -609,6 +626,13 @@ static inline bool br_allowed_egress(struct net_bridge *br,
return true;
}

static inline struct sk_buff *br_handle_vlan(struct net_bridge *br,
const struct net_port_vlans *v,
struct sk_buff *skb)
{
return skb;
}

static inline int br_vlan_add(struct net_bridge *br, u16 vid)
{
return -EOPNOTSUPP;
Expand Down Expand Up @@ -648,10 +672,14 @@ static inline struct net_port_vlans *nbp_get_vlan_info(
return NULL;
}

static inline u16 br_vlan_get_tag(const struct sk_buff *skb)
static inline u16 br_vlan_get_tag(const struct sk_buff *skb, u16 *tag)
{
return 0;
}
static inline u16 br_get_pvid(const struct net_port_vlans *v)
{
return VLAN_N_VID; /* Returns invalid vid */
}
#endif

/* br_netfilter.c */
Expand Down
83 changes: 78 additions & 5 deletions trunk/net/bridge/br_vlan.c
Original file line number Diff line number Diff line change
Expand Up @@ -66,12 +66,68 @@ static void __vlan_flush(struct net_port_vlans *v)
kfree_rcu(v, rcu);
}

/* Called under RCU */
bool br_allowed_ingress(struct net_bridge *br, struct net_port_vlans *v,
struct sk_buff *skb)
/* Strip the tag from the packet. Will return skb with tci set 0. */
static struct sk_buff *br_vlan_untag(struct sk_buff *skb)
{
if (skb->protocol != htons(ETH_P_8021Q)) {
skb->vlan_tci = 0;
return skb;
}

skb->vlan_tci = 0;
skb = vlan_untag(skb);
if (skb)
skb->vlan_tci = 0;

return skb;
}

struct sk_buff *br_handle_vlan(struct net_bridge *br,
const struct net_port_vlans *pv,
struct sk_buff *skb)
{
u16 vid;

if (!br->vlan_enabled)
goto out;

/* At this point, we know that the frame was filtered and contains
* a valid vlan id. If the vlan id matches the pvid of current port
* send untagged; otherwise, send taged.
*/
br_vlan_get_tag(skb, &vid);
if (vid == br_get_pvid(pv))
skb = br_vlan_untag(skb);
else {
/* Egress policy says "send tagged". If output device
* is the bridge, we need to add the VLAN header
* ourselves since we'll be going through the RX path.
* Sending to ports puts the frame on the TX path and
* we let dev_hard_start_xmit() add the header.
*/
if (skb->protocol != htons(ETH_P_8021Q) &&
pv->port_idx == 0) {
/* vlan_put_tag expects skb->data to point to
* mac header.
*/
skb_push(skb, ETH_HLEN);
skb = __vlan_put_tag(skb, skb->vlan_tci);
if (!skb)
goto out;
/* put skb->data back to where it was */
skb_pull(skb, ETH_HLEN);
skb->vlan_tci = 0;
}
}

out:
return skb;
}

/* Called under RCU */
bool br_allowed_ingress(struct net_bridge *br, struct net_port_vlans *v,
struct sk_buff *skb, u16 *vid)
{
/* If VLAN filtering is disabled on the bridge, all packets are
* permitted.
*/
Expand All @@ -84,8 +140,25 @@ bool br_allowed_ingress(struct net_bridge *br, struct net_port_vlans *v,
if (!v)
return false;

br_vlan_get_tag(skb, &vid);
if (test_bit(vid, v->vlan_bitmap))
if (br_vlan_get_tag(skb, vid)) {
u16 pvid = br_get_pvid(v);

/* Frame did not have a tag. See if pvid is set
* on this port. That tells us which vlan untagged
* traffic belongs to.
*/
if (pvid == VLAN_N_VID)
return false;

/* PVID is set on this port. Any untagged ingress
* frame is considered to belong to this vlan.
*/
__vlan_hwaccel_put_tag(skb, pvid);
return true;
}

/* Frame had a valid vlan tag. See if vlan is allowed */
if (test_bit(*vid, v->vlan_bitmap))
return true;

return false;
Expand Down

0 comments on commit b5479ec

Please sign in to comment.