Exemple #1
0
/* Obtain the correct destination MAC address, while preserving the original
 * source MAC address. If we already know this address, we just copy it. If we
 * don't, we use the neighbour framework to find out. In both cases, we make
 * sure that br_handle_frame_finish() is called afterwards.
 */
static int br_nf_pre_routing_finish_bridge(struct sk_buff *skb)
{
	struct nf_bridge_info *nf_bridge = skb->nf_bridge;
	struct dst_entry *dst;

	skb->dev = bridge_parent(skb->dev);
	if (!skb->dev)
		goto free_skb;
	dst = skb_dst(skb);
	if (dst->hh) {
		neigh_hh_bridge(dst->hh, skb);
		skb->dev = nf_bridge->physindev;
		return br_handle_frame_finish(skb);
	} else if (dst->neighbour) {
		/* the neighbour function below overwrites the complete
		 * MAC header, so we save the Ethernet source address and
		 * protocol number. */
		skb_copy_from_linear_data_offset(skb, -(ETH_HLEN-ETH_ALEN), skb->nf_bridge->data, ETH_HLEN-ETH_ALEN);
		/* tell br_dev_xmit to continue with forwarding */
		nf_bridge->mask |= BRNF_BRIDGED_DNAT;
		return dst->neighbour->output(skb);
	}
free_skb:
	kfree_skb(skb);
	return 0;
}
/* Obtain the correct destination MAC address, while preserving the original
 * source MAC address. If we already know this address, we just copy it. If we
 * don't, we use the neighbour framework to find out. In both cases, we make
 * sure that br_handle_frame_finish() is called afterwards.
 */
int br_nf_pre_routing_finish_bridge(struct net *net, struct sock *sk, struct sk_buff *skb)
{
	struct neighbour *neigh;
	struct dst_entry *dst;

	skb->dev = bridge_parent(skb->dev);
	if (!skb->dev)
		goto free_skb;
	dst = skb_dst(skb);
	neigh = dst_neigh_lookup_skb(dst, skb);
	if (neigh) {
		struct nf_bridge_info *nf_bridge = nf_bridge_info_get(skb);
		int ret;

		if (neigh->hh.hh_len) {
			neigh_hh_bridge(&neigh->hh, skb);
			skb->dev = nf_bridge->physindev;
			ret = br_handle_frame_finish(net, sk, skb);
		} else {
			/* the neighbour function below overwrites the complete
			 * MAC header, so we save the Ethernet source address and
			 * protocol number.
			 */
			skb_copy_from_linear_data_offset(skb,
							 -(ETH_HLEN-ETH_ALEN),
							 nf_bridge->neigh_header,
							 ETH_HLEN-ETH_ALEN);
			/* tell br_dev_xmit to continue with forwarding */
			nf_bridge->bridged_dnat = 1;
			/* FIXME Need to refragment */
			ret = neigh->output(neigh, skb);
		}
		neigh_release(neigh);
		return ret;
	}
free_skb:
	kfree_skb(skb);
	return 0;
}