static int __br_dev_xmit(struct sk_buff *skb, struct net_device *dev) { struct net_bridge *br; unsigned char *dest; struct net_bridge_fdb_entry *dst; br = dev->priv; br->statistics.tx_packets++; br->statistics.tx_bytes += skb->len; dest = skb->mac.raw = skb->data; skb_pull(skb, ETH_HLEN); if (dest[0] & 1) { br_flood_deliver(br, skb, 0); return 0; } if ((dst = br_fdb_get(br, dest)) != NULL) { br_deliver(dst->dst, skb); br_fdb_put(dst); return 0; } br_flood_deliver(br, skb, 0); return 0; }
void br_fdb_cleanup(struct net_bridge *br) { int i; unsigned long timeout; timeout = __timeout(br); write_lock_bh(&br->hash_lock); for (i=0;i<BR_HASH_SIZE;i++) { struct net_bridge_fdb_entry *f; f = br->hash[i]; while (f != NULL) { struct net_bridge_fdb_entry *g; g = f->next_hash; if (!f->is_static && time_before_eq(f->ageing_timer, timeout)) { __hash_unlink(f); br_fdb_put(f); } f = g; } } write_unlock_bh(&br->hash_lock); }
void br_fdb_delete_by_port(struct net_bridge *br, struct net_bridge_port *p) { int i; write_lock_bh(&br->hash_lock); for (i=0;i<BR_HASH_SIZE;i++) { struct net_bridge_fdb_entry *f; f = br->hash[i]; while (f != NULL) { struct net_bridge_fdb_entry *g; g = f->next_hash; if (f->dst == p) { __hash_unlink(f); br_fdb_put(f); } f = g; } } write_unlock_bh(&br->hash_lock); }
static int br_handle_frame_finish(struct sk_buff *skb) { struct net_bridge *br; unsigned char *dest; struct net_bridge_fdb_entry *dst; struct net_bridge_port *p; int passedup; dest = skb->mac.ethernet->h_dest; p = skb->dev->br_port; if (p == NULL) goto err_nolock; br = p->br; read_lock(&br->lock); if (skb->dev->br_port == NULL) goto err; passedup = 0; if (br->dev.flags & IFF_PROMISC) { struct sk_buff *skb2; skb2 = skb_clone(skb, GFP_ATOMIC); if (skb2 != NULL) { passedup = 1; br_pass_frame_up(br, skb2); } } if (dest[0] & 1) { br_flood_forward(br, skb, !passedup); if (!passedup) br_pass_frame_up(br, skb); goto out; } dst = br_fdb_get(br, dest); if (dst != NULL && dst->is_local) { if (!passedup) br_pass_frame_up(br, skb); else kfree_skb(skb); br_fdb_put(dst); goto out; } if (dst != NULL) { br_forward(dst->dst, skb); br_fdb_put(dst); goto out; } br_flood_forward(br, skb, 0); out: read_unlock(&br->lock); return 0; err: read_unlock(&br->lock); err_nolock: kfree_skb(skb); return 0; }
static int __br_dev_xmit(struct sk_buff *skb, struct net_device *dev) { struct net_bridge *br; unsigned char *dest; struct net_bridge_fdb_entry *dst; #ifdef IGMP_SNOOPING struct iphdr *iph; unsigned int ipaddr=0; unsigned char proto=0; //unsigned char reserved=0; extern int igmpsnoopenabled; iph = skb->nh.iph; ipaddr = iph->daddr; proto = iph->protocol; //Brad disable 20080619 // if ((ipaddr&0xF0FFFF00) == 0xE0000000) // reserved=1; #endif br = dev->priv; br->statistics.tx_packets++; br->statistics.tx_bytes += skb->len; dest = skb->mac.raw = skb->data; skb_pull(skb, ETH_HLEN); if (dest[0] & 1) { #ifdef IGMP_SNOOPING if(igmpsnoopenabled && (MULTICAST_MAC(dest) || IPV6_MULTICAST_MAC(dest))&& (proto != IPPROTO_IGMP) && (ipaddr != 0xEFFFFFFA) //&& (reserved == 0) ) { if ((dst = br_fdb_get(br, dest)) != NULL) { br_multicast_deliver(br, dst, skb, 0); br_fdb_put(dst); } else { br_flood_deliver(br, skb, 0); } } else { // broadcast br_flood_deliver(br, skb, 0); } return 0; #else br_flood_deliver(br, skb, 0); return 0; #endif } if ((dst = br_fdb_get(br, dest)) != NULL) { #ifdef NAT_SPEEDUP if (skb->dst && skb->dst->hh && skb->dst->hh->fdb_cache==NULL) { skb->dst->hh->fdb_cache = (void*)dst; dst->hh_ptr = skb->dst->hh; } #endif br_deliver(dst->dst, skb); br_fdb_put(dst); return 0; } br_flood_deliver(br, skb, 0); return 0; }
int br_fdb_get_entries(struct net_bridge *br, unsigned char *_buf, int maxnum, int offset) { int i; int num; struct __fdb_entry *walk; num = 0; walk = (struct __fdb_entry *)_buf; read_lock_bh(&br->hash_lock); for (i=0;i<BR_HASH_SIZE;i++) { struct net_bridge_fdb_entry *f; f = br->hash[i]; while (f != NULL && num < maxnum) { struct __fdb_entry ent; int err; struct net_bridge_fdb_entry *g; struct net_bridge_fdb_entry **pp; if (has_expired(br, f)) { f = f->next_hash; continue; } if (offset) { offset--; f = f->next_hash; continue; } copy_fdb(&ent, f); atomic_inc(&f->use_count); read_unlock_bh(&br->hash_lock); err = copy_to_user(walk, &ent, sizeof(struct __fdb_entry)); read_lock_bh(&br->hash_lock); g = f->next_hash; pp = f->pprev_hash; br_fdb_put(f); if (err) goto out_fault; if (g == NULL && pp == NULL) goto out_disappeared; num++; walk++; f = g; } } out: read_unlock_bh(&br->hash_lock); return num; out_disappeared: num = -EAGAIN; goto out; out_fault: num = -EFAULT; goto out; }