/* net device transmit always called with no BH (preempt_disabled) */ int br_dev_xmit(struct sk_buff *skb, struct net_device *dev) { struct net_bridge *br = netdev_priv(dev); const unsigned char *dest = skb->data; struct net_bridge_fdb_entry *dst; #if defined(CONFIG_MIPS_BRCM) && defined(CONFIG_BLOG) blog_dev( skb, dev, DIR_TX, skb->len ); #endif dev->stats.tx_packets++; dev->stats.tx_bytes += skb->len; skb_reset_mac_header(skb); skb_pull(skb, ETH_HLEN); #if defined(CONFIG_MIPS_BRCM) && defined(CONFIG_BR_MLD_SNOOP) if ((0x33 == dest[0]) && (0x33 == dest[1])) { if (!br_mld_mc_forward(br, skb, 0, 0)) br_flood_deliver(br, skb); } else #endif if (dest[0] & 1) { #if defined(CONFIG_MIPS_BRCM) && defined(CONFIG_BR_IGMP_SNOOP) if (!br_igmp_mc_forward(br, skb, 0, 0)) #endif br_flood_deliver(br, skb); } else if ((dst = __br_fdb_get(br, dest)) != NULL) br_deliver(dst->dst, skb); else br_flood_deliver(br, skb); return 0; }
/* note: already called with rcu_read_lock (preempt_disabled) */ int br_handle_frame_finish(struct sk_buff *skb) { const unsigned char *dest = eth_hdr(skb)->h_dest; struct net_bridge_port *p = rcu_dereference(skb->dev->br_port); struct net_bridge *br; struct net_bridge_fdb_entry *dst; struct sk_buff *skb2; if (!p || p->state == BR_STATE_DISABLED) goto drop; /* insert into forwarding database after filtering to avoid spoofing */ br = p->br; br_fdb_update(br, p, eth_hdr(skb)->h_source); if (p->state == BR_STATE_LEARNING) goto drop; /* The packet skb2 goes to the local host (NULL to skip). */ skb2 = NULL; if (br->dev->flags & IFF_PROMISC) skb2 = skb; dst = NULL; #if defined(CONFIG_MIPS_BRCM) && defined(CONFIG_BR_MLD_SNOOP) if((0x33 == dest[0]) && (0x33 == dest[1])) { br->statistics.multicast++; skb2 = skb; if (br_mld_mc_forward(br, skb, 1, 0)) { skb = NULL; } } else #endif if (is_multicast_ether_addr(dest)) { br->dev->stats.multicast++; skb2 = skb; #if defined(CONFIG_MIPS_BRCM) && defined(CONFIG_BR_IGMP_SNOOP) if (br_igmp_mc_forward(br, skb, 1, 0)) { skb = NULL; } #endif } else { dst = __br_fdb_get(br, dest); #if defined(CONFIG_MIPS_BRCM) && defined(CONFIG_BLOG) blog_br_fdb(skb, __br_fdb_get(br, eth_hdr(skb)->h_source), dst); #endif if ((dst != NULL) && dst->is_local) { skb2 = skb; /* Do not forward the packet since it's local. */ skb = NULL; } } if (skb2 == skb) skb2 = skb_clone(skb, GFP_ATOMIC); if (skb2) br_pass_frame_up(br, skb2); if (skb) { if (dst) br_forward(dst->dst, skb); else br_flood_forward(br, skb); } out: return 0; drop: kfree_skb(skb); goto out; }