Beispiel #1
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;

	br = dev->priv;
	br->statistics.tx_packets++;
	br->statistics.tx_bytes += skb->len;

	dest = skb->data;

	if (dest[0] & 1) {
		br_flood(br, skb, 0);
		return 0;
	}

	if ((dst = br_fdb_get(br, dest)) != NULL) {
		br_forward(dst->dst, skb);
		br_fdb_put(dst);
		return 0;
	}

	br_flood(br, skb, 0);
	return 0;
}
void br_flood_forward(struct net_bridge *br, struct sk_buff *skb, int clone)
{
	br_flood(br, skb, clone, __br_forward);
}
void br_flood_deliver(struct net_bridge *br, struct sk_buff *skb, int clone)
{
	br_flood(br, skb, clone, __br_deliver);
}
Beispiel #4
0
Datei: br.c Projekt: rcacho/book
static int br_forward(void *pkt, int len, int port)	/* 3.7 */
{
	struct fdb *f;
	struct ethhdr *eth;
	eth = (struct ethhdr*)pkt;	
#ifdef BR_DEBUG
	debug_print("br_forward be call.... \r\n");
#endif

	
	
	/*
   	 * flood all ports with frames destined for a group
	 * address.  If frame came from above, drop it,
	 * otherwise it will be handled in br_receive_frame()
	 * Multicast frames will also need to be seen
	 * by our upper layers.
	 */	
	if (eth->ether_dhost[0] & 0x01) 
	{
#ifdef BR_DEBUG
		debug_print("dest is group address .... \r\n");
#endif


                /* group address */
                br_flood(pkt,len, port);
                /*
                 *      External groups are fed out via the normal source
                 *      This probably should be dropped since the flood will
                 *      have sent it anyway.
                 */
                if (port == 0)
                {
                        /* Locally generated */
                        ++br_stats_cnt.local_multicast;
                        return(0);
                }
                ++br_stats_cnt.forwarded_multicast;
		return(0);
	}
	else 
	{
		/* unicast frame, locate port to forward to */
		f = br_find_addr(eth->ether_dhost);
		/*
		 *	Send flood and drop.
		 */
		if (!f || !(f->flags & FDB_ENT_VALID)) 
		{
	 		if(f && (f->port == 0)) 
	 		{
				++br_stats_cnt.forwarded_unicast_up_stack;
#ifdef BR_DEBUG
				debug_print("br: port is invaild .. \r\n");
#endif

				return(0);
			}
			/* not found or too old; flood all ports */
			++br_stats_cnt.flood_unicast;

			debug_print("br_flood packet ... \r\n");

			br_flood(pkt,len, port);

			return(0);
		}

		/*
		 *	Sending
		 */
		if (f->port!=port && port_info[f->port].state == Forwarding) 
		{
			struct nic *dev;
#ifdef BR_DEBUG
			debug_print("br: the dest in diffrent port , so forward it .. \r\n");
#endif

			/* Has entry expired? */
			if (f->timer + fdb_aging_time < CURRENT_TIME) 
			{
#ifdef BR_DEBUG
				debug_print("br: port have invaild .. \r\n");
#endif
				/* timer expired, invalidate entry */
				f->flags &= ~FDB_ENT_VALID;
				/*
				 *	Send flood and drop original
				 */
				++br_stats_cnt.aged_flood_unicast;
				br_flood(pkt,len, port);
				return(0);
			}

			++br_stats_cnt.forwarded_unicast;

			/*
			 *	Send the buffer out.
			 */
			 
			dev = port_info[f->port].dev;

#ifdef BR_DEBUG
			debug_print("br: every thing is ok , forward it  .. \r\n");
#endif
			dev->transmit(dev,pkt,len);

			return(1);	/* skb has been consumed */
		}
		else 
		{

#ifdef BR_DEBUG
			debug_print("br: dest in same port .. \r\n");
#endif
			/* JRP: Needs to aged entry as well, if topology changes
			 * the entry would not age. Got this while swapping
			 * two cables !
			 *
			 *	Has entry expired?
			 */
			 
			if (f->timer + fdb_aging_time < CURRENT_TIME) 
			{
				/* timer expired, invalidate entry */
				f->flags &= ~FDB_ENT_VALID;
				++br_stats_cnt.drop_same_port_aged;
			}
			else 
				++br_stats_cnt.drop_same_port;
			/*
			 *	Arrived on the right port, we discard
			 */
			return(0);
		}
	}

}
Beispiel #5
0
/* note: already called with rcu_read_lock */
int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb)
{
	bool local_rcv = false, mcast_hit = false, unicast = true;
	struct net_bridge_port *p = br_port_get_rcu(skb->dev);
	const unsigned char *dest = eth_hdr(skb)->h_dest;
	struct net_bridge_fdb_entry *dst = NULL;
	struct net_bridge_mdb_entry *mdst;
	struct net_bridge *br;
	u16 vid = 0;

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

	if (!br_allowed_ingress(p->br, nbp_vlan_group_rcu(p), skb, &vid))
		goto out;

	/* insert into forwarding database after filtering to avoid spoofing */
	br = p->br;
	if (p->flags & BR_LEARNING)
		br_fdb_update(br, p, eth_hdr(skb)->h_source, vid, false);

	if (!is_broadcast_ether_addr(dest) && is_multicast_ether_addr(dest) &&
	    br_multicast_rcv(br, p, skb, vid))
		goto drop;

	if (p->state == BR_STATE_LEARNING)
		goto drop;

	BR_INPUT_SKB_CB(skb)->brdev = br->dev;

	local_rcv = !!(br->dev->flags & IFF_PROMISC);

	if (IS_ENABLED(CONFIG_INET) && skb->protocol == htons(ETH_P_ARP))
		br_do_proxy_arp(skb, br, vid, p);

	if (is_broadcast_ether_addr(dest)) {
		local_rcv = true;
		unicast = false;
	} else if (is_multicast_ether_addr(dest)) {
		mdst = br_mdb_get(br, skb, vid);
		if ((mdst || BR_INPUT_SKB_CB_MROUTERS_ONLY(skb)) &&
		    br_multicast_querier_exists(br, eth_hdr(skb))) {
			if ((mdst && mdst->mglist) ||
			    br_multicast_is_router(br)) {
				local_rcv = true;
				br->dev->stats.multicast++;
			}
			mcast_hit = true;
		} else {
			local_rcv = true;
			br->dev->stats.multicast++;
		}
		unicast = false;
	} else if ((dst = __br_fdb_get(br, dest, vid)) && dst->is_local) {
		/* Do not forward the packet since it's local. */
		return br_pass_frame_up(skb);
	}

	if (dst) {
		dst->used = jiffies;
		br_forward(dst->dst, skb, local_rcv, false);
	} else {
		if (!mcast_hit)
			br_flood(br, skb, unicast, local_rcv, false);
		else
			br_multicast_flood(mdst, skb, local_rcv, false);
	}

	if (local_rcv)
		return br_pass_frame_up(skb);

out:
	return 0;
drop:
	kfree_skb(skb);
	goto out;
}
Beispiel #6
0
/* note: already called with rcu_read_lock */
int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb)
{
	struct net_bridge_port *p = br_port_get_rcu(skb->dev);
	enum br_pkt_type pkt_type = BR_PKT_UNICAST;
	struct net_bridge_fdb_entry *dst = NULL;
	struct net_bridge_mdb_entry *mdst;
	bool local_rcv, mcast_hit = false;
	const unsigned char *dest;
	struct net_bridge *br;
	u16 vid = 0;

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

	if (!br_allowed_ingress(p->br, nbp_vlan_group_rcu(p), skb, &vid))
		goto out;

	nbp_switchdev_frame_mark(p, skb);

	/* insert into forwarding database after filtering to avoid spoofing */
	br = p->br;
	if (p->flags & BR_LEARNING)
		br_fdb_update(br, p, eth_hdr(skb)->h_source, vid, false);

	local_rcv = !!(br->dev->flags & IFF_PROMISC);
	dest = eth_hdr(skb)->h_dest;
	if (is_multicast_ether_addr(dest)) {
		/* by definition the broadcast is also a multicast address */
		if (is_broadcast_ether_addr(dest)) {
			pkt_type = BR_PKT_BROADCAST;
			local_rcv = true;
		} else {
			pkt_type = BR_PKT_MULTICAST;
			if (br_multicast_rcv(br, p, skb, vid))
				goto drop;
		}
	}

	if (p->state == BR_STATE_LEARNING)
		goto drop;

	BR_INPUT_SKB_CB(skb)->brdev = br->dev;

	if (IS_ENABLED(CONFIG_INET) && skb->protocol == htons(ETH_P_ARP))
		br_do_proxy_arp(skb, br, vid, p);

	switch (pkt_type) {
	case BR_PKT_MULTICAST:
		mdst = br_mdb_get(br, skb, vid);
		if ((mdst || BR_INPUT_SKB_CB_MROUTERS_ONLY(skb)) &&
		    br_multicast_querier_exists(br, eth_hdr(skb))) {
			if ((mdst && mdst->mglist) ||
			    br_multicast_is_router(br)) {
				local_rcv = true;
				br->dev->stats.multicast++;
			}
			mcast_hit = true;
		} else {
			local_rcv = true;
			br->dev->stats.multicast++;
		}
		break;
	case BR_PKT_UNICAST:
		dst = br_fdb_find_rcu(br, dest, vid);
	default:
		break;
	}

	if (dst) {
		unsigned long now = jiffies;

		if (dst->is_local)
			return br_pass_frame_up(skb);

		if (now != dst->used)
			dst->used = now;
		br_forward(dst->dst, skb, local_rcv, false);
	} else {
		if (!mcast_hit)
			br_flood(br, skb, pkt_type, local_rcv, false);
		else
			br_multicast_flood(mdst, skb, local_rcv, false);
	}

	if (local_rcv)
		return br_pass_frame_up(skb);

out:
	return 0;
drop:
	kfree_skb(skb);
	goto out;
}