Release 4.8 net/bridge/br_input.c
/*
* Handle incoming frames
* Linux ethernet bridge
*
* Authors:
* Lennert Buytenhek <buytenh@gnu.org>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/netfilter_bridge.h>
#include <linux/neighbour.h>
#include <net/arp.h>
#include <linux/export.h>
#include <linux/rculist.h>
#include "br_private.h"
/* Hook for brouter */
br_should_route_hook_t __rcu *br_should_route_hook __read_mostly;
EXPORT_SYMBOL(br_should_route_hook);
static int
br_netif_receive_skb(struct net *net, struct sock *sk, struct sk_buff *skb)
{
return netif_receive_skb(skb);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
eric w. biederman | eric w. biederman | 27 | 100.00% | 2 | 100.00% |
| Total | 27 | 100.00% | 2 | 100.00% |
static int br_pass_frame_up(struct sk_buff *skb)
{
struct net_device *indev, *brdev = BR_INPUT_SKB_CB(skb)->brdev;
struct net_bridge *br = netdev_priv(brdev);
struct net_bridge_vlan_group *vg;
struct pcpu_sw_netstats *brstats = this_cpu_ptr(br->stats);
u64_stats_update_begin(&brstats->syncp);
brstats->rx_packets++;
brstats->rx_bytes += skb->len;
u64_stats_update_end(&brstats->syncp);
vg = br_vlan_group_rcu(br);
/* Bridge is just like any other port. Make sure the
* packet is allowed except in promisc modue when someone
* may be running packet capture.
*/
if (!(brdev->flags & IFF_PROMISC) &&
!br_allowed_egress(vg, skb)) {
kfree_skb(skb);
return NET_RX_DROP;
}
indev = skb->dev;
skb->dev = brdev;
skb = br_handle_vlan(br, vg, skb);
if (!skb)
return NET_RX_DROP;
/* update the multicast stats if the packet is IGMP/MLD */
br_multicast_count(br, NULL, skb, br_multicast_igmp_type(skb),
BR_MCAST_DIR_TX);
return NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_IN,
dev_net(indev), NULL, skb, indev, NULL,
br_netif_receive_skb);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
vlad yasevich | vlad yasevich | 63 | 33.16% | 3 | 17.65% |
nikolay aleksandrov | nikolay aleksandrov | 27 | 14.21% | 3 | 17.65% |
pre-git | pre-git | 24 | 12.63% | 1 | 5.88% |
stephen hemminger | stephen hemminger | 21 | 11.05% | 1 | 5.88% |
eric dumazet | eric dumazet | 16 | 8.42% | 1 | 5.88% |
linus torvalds | linus torvalds | 13 | 6.84% | 1 | 5.88% |
pavel emelianov | pavel emelianov | 8 | 4.21% | 1 | 5.88% |
herbert xu | herbert xu | 8 | 4.21% | 1 | 5.88% |
eric w. biederman | eric w. biederman | 6 | 3.16% | 2 | 11.76% |
david s. miller | david s. miller | 2 | 1.05% | 1 | 5.88% |
li rongqing | li rongqing | 1 | 0.53% | 1 | 5.88% |
jan engelhardt | jan engelhardt | 1 | 0.53% | 1 | 5.88% |
| Total | 190 | 100.00% | 17 | 100.00% |
static void br_do_proxy_arp(struct sk_buff *skb, struct net_bridge *br,
u16 vid, struct net_bridge_port *p)
{
struct net_device *dev = br->dev;
struct neighbour *n;
struct arphdr *parp;
u8 *arpptr, *sha;
__be32 sip, tip;
BR_INPUT_SKB_CB(skb)->proxyarp_replied = false;
if ((dev->flags & IFF_NOARP) ||
!pskb_may_pull(skb, arp_hdr_len(dev)))
return;
parp = arp_hdr(skb);
if (parp->ar_pro != htons(ETH_P_IP) ||
parp->ar_op != htons(ARPOP_REQUEST) ||
parp->ar_hln != dev->addr_len ||
parp->ar_pln != 4)
return;
arpptr = (u8 *)parp + sizeof(struct arphdr);
sha = arpptr;
arpptr += dev->addr_len; /* sha */
memcpy(&sip, arpptr, sizeof(sip));
arpptr += sizeof(sip);
arpptr += dev->addr_len; /* tha */
memcpy(&tip, arpptr, sizeof(tip));
if (ipv4_is_loopback(tip) ||
ipv4_is_multicast(tip))
return;
n = neigh_lookup(&arp_tbl, &tip, dev);
if (n) {
struct net_bridge_fdb_entry *f;
if (!(n->nud_state & NUD_VALID)) {
neigh_release(n);
return;
}
f = __br_fdb_get(br, n->ha, vid);
if (f && ((p->flags & BR_PROXYARP) ||
(f->dst && (f->dst->flags & BR_PROXYARP_WIFI)))) {
arp_send(ARPOP_REPLY, ETH_P_ARP, sip, skb->dev, tip,
sha, n->ha, sha);
BR_INPUT_SKB_CB(skb)->proxyarp_replied = true;
}
neigh_release(n);
}
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
kyeyoon park | kyeyoon park | 277 | 83.69% | 1 | 33.33% |
jouni malinen | jouni malinen | 51 | 15.41% | 1 | 33.33% |
nikolay aleksandrov | nikolay aleksandrov | 3 | 0.91% | 1 | 33.33% |
| Total | 331 | 100.00% | 3 | 100.00% |
/* 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;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
herbert xu | herbert xu | 109 | 23.34% | 6 | 13.64% |
nikolay aleksandrov | nikolay aleksandrov | 101 | 21.63% | 6 | 13.64% |
stephen hemminger | stephen hemminger | 84 | 17.99% | 8 | 18.18% |
pre-git | pre-git | 56 | 11.99% | 2 | 4.55% |
vlad yasevich | vlad yasevich | 39 | 8.35% | 6 | 13.64% |
kyeyoon park | kyeyoon park | 18 | 3.85% | 1 | 2.27% |
linus lussing | linus lussing | 12 | 2.57% | 2 | 4.55% |
jouni malinen | jouni malinen | 10 | 2.14% | 1 | 2.27% |
linus torvalds | linus torvalds | 9 | 1.93% | 1 | 2.27% |
david s. miller | david s. miller | 5 | 1.07% | 1 | 2.27% |
arnd bergmann | arnd bergmann | 5 | 1.07% | 1 | 2.27% |
eric w. biederman | eric w. biederman | 5 | 1.07% | 1 | 2.27% |
toshiaki makita | toshiaki makita | 3 | 0.64% | 2 | 4.55% |
kris katterjohn | kris katterjohn | 3 | 0.64% | 1 | 2.27% |
pavel emelianov | pavel emelianov | 3 | 0.64% | 1 | 2.27% |
americo wang | americo wang | 2 | 0.43% | 1 | 2.27% |
michael braun | michael braun | 1 | 0.21% | 1 | 2.27% |
hideaki yoshifuji | hideaki yoshifuji | 1 | 0.21% | 1 | 2.27% |
jiri pirko | jiri pirko | 1 | 0.21% | 1 | 2.27% |
| Total | 467 | 100.00% | 44 | 100.00% |
EXPORT_SYMBOL_GPL(br_handle_frame_finish);
static void __br_handle_local_finish(struct sk_buff *skb)
{
struct net_bridge_port *p = br_port_get_rcu(skb->dev);
u16 vid = 0;
/* check if vlan is allowed, to avoid spoofing */
if (p->flags & BR_LEARNING && br_should_learn(p, skb, &vid))
br_fdb_update(p->br, p, eth_hdr(skb)->h_source, vid, false);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
stephen hemminger | stephen hemminger | 35 | 52.24% | 1 | 14.29% |
vlad yasevich | vlad yasevich | 15 | 22.39% | 2 | 28.57% |
toshiaki makita | toshiaki makita | 13 | 19.40% | 2 | 28.57% |
ido schimmel | ido schimmel | 3 | 4.48% | 1 | 14.29% |
jiri pirko | jiri pirko | 1 | 1.49% | 1 | 14.29% |
| Total | 67 | 100.00% | 7 | 100.00% |
/* note: already called with rcu_read_lock */
static int br_handle_local_finish(struct net *net, struct sock *sk, struct sk_buff *skb)
{
struct net_bridge_port *p = br_port_get_rcu(skb->dev);
__br_handle_local_finish(skb);
BR_INPUT_SKB_CB(skb)->brdev = p->br->dev;
br_pass_frame_up(skb);
return 0;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
ido schimmel | ido schimmel | 37 | 62.71% | 1 | 33.33% |
florian westphal | florian westphal | 18 | 30.51% | 1 | 33.33% |
stephen hemminger | stephen hemminger | 4 | 6.78% | 1 | 33.33% |
| Total | 59 | 100.00% | 3 | 100.00% |
/*
* Return NULL if skb is handled
* note: already called with rcu_read_lock
*/
rx_handler_result_t br_handle_frame(struct sk_buff **pskb)
{
struct net_bridge_port *p;
struct sk_buff *skb = *pskb;
const unsigned char *dest = eth_hdr(skb)->h_dest;
br_should_route_hook_t *rhook;
if (unlikely(skb->pkt_type == PACKET_LOOPBACK))
return RX_HANDLER_PASS;
if (!is_valid_ether_addr(eth_hdr(skb)->h_source))
goto drop;
skb = skb_share_check(skb, GFP_ATOMIC);
if (!skb)
return RX_HANDLER_CONSUMED;
p = br_port_get_rcu(skb->dev);
if (unlikely(is_link_local_ether_addr(dest))) {
u16 fwd_mask = p->br->group_fwd_mask_required;
/*
* See IEEE 802.1D Table 7-10 Reserved addresses
*
* Assignment Value
* Bridge Group Address 01-80-C2-00-00-00
* (MAC Control) 802.3 01-80-C2-00-00-01
* (Link Aggregation) 802.3 01-80-C2-00-00-02
* 802.1X PAE address 01-80-C2-00-00-03
*
* 802.1AB LLDP 01-80-C2-00-00-0E
*
* Others reserved for future standardization
*/
switch (dest[5]) {
case 0x00: /* Bridge Group Address */
/* If STP is turned off,
then must forward to keep loop detection */
if (p->br->stp_enabled == BR_NO_STP ||
fwd_mask & (1u << dest[5]))
goto forward;
*pskb = skb;
__br_handle_local_finish(skb);
return RX_HANDLER_PASS;
case 0x01: /* IEEE MAC (Pause) */
goto drop;
case 0x0E: /* 802.1AB LLDP */
fwd_mask |= p->br->group_fwd_mask;
if (fwd_mask & (1u << dest[5]))
goto forward;
*pskb = skb;
__br_handle_local_finish(skb);
return RX_HANDLER_PASS;
default:
/* Allow selective forwarding for most other protocols */
fwd_mask |= p->br->group_fwd_mask;
if (fwd_mask & (1u << dest[5]))
goto forward;
}
/* Deliver packet to local host only */
NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_IN, dev_net(skb->dev),
NULL, skb, skb->dev, NULL, br_handle_local_finish);
return RX_HANDLER_CONSUMED;
}
forward:
switch (p->state) {
case BR_STATE_FORWARDING:
rhook = rcu_dereference(br_should_route_hook);
if (rhook) {
if ((*rhook)(skb)) {
*pskb = skb;
return RX_HANDLER_PASS;
}
dest = eth_hdr(skb)->h_dest;
}
/* fall through */
case BR_STATE_LEARNING:
if (ether_addr_equal(p->br->dev->dev_addr, dest))
skb->pkt_type = PACKET_HOST;
NF_HOOK(NFPROTO_BRIDGE, NF_BR_PRE_ROUTING,
dev_net(skb->dev), NULL, skb, skb->dev, NULL,
br_handle_frame_finish);
break;
default:
drop:
kfree_skb(skb);
}
return RX_HANDLER_CONSUMED;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
stephen hemminger | stephen hemminger | 112 | 28.57% | 12 | 33.33% |
ido schimmel | ido schimmel | 54 | 13.78% | 2 | 5.56% |
jiri pirko | jiri pirko | 49 | 12.50% | 3 | 8.33% |
linus torvalds | linus torvalds | 45 | 11.48% | 2 | 5.56% |
bart de schuymer | bart de schuymer | 27 | 6.89% | 3 | 8.33% |
toshiaki makita | toshiaki makita | 26 | 6.63% | 1 | 2.78% |
herbert xu | herbert xu | 16 | 4.08% | 1 | 2.78% |
eric w. biederman | eric w. biederman | 14 | 3.57% | 1 | 2.78% |
pavel emelianov | pavel emelianov | 11 | 2.81% | 1 | 2.78% |
arnaldo carvalho de melo | arnaldo carvalho de melo | 9 | 2.30% | 1 | 2.78% |
david s. miller | david s. miller | 8 | 2.04% | 2 | 5.56% |
pre-git | pre-git | 8 | 2.04% | 1 | 2.78% |
eric dumazet | eric dumazet | 5 | 1.28% | 1 | 2.78% |
simon horman | simon horman | 3 | 0.77% | 1 | 2.78% |
jan engelhardt | jan engelhardt | 2 | 0.51% | 1 | 2.78% |
ben hutchings | ben hutchings | 1 | 0.26% | 1 | 2.78% |
florian westphal | florian westphal | 1 | 0.26% | 1 | 2.78% |
joe perches | joe perches | 1 | 0.26% | 1 | 2.78% |
| Total | 392 | 100.00% | 36 | 100.00% |
Overall Contributors
| Person | Tokens | Prop | Commits | CommitProp |
kyeyoon park | kyeyoon park | 301 | 19.00% | 1 | 1.11% |
stephen hemminger | stephen hemminger | 257 | 16.22% | 20 | 22.22% |
herbert xu | herbert xu | 133 | 8.40% | 7 | 7.78% |
nikolay aleksandrov | nikolay aleksandrov | 131 | 8.27% | 9 | 10.00% |
vlad yasevich | vlad yasevich | 120 | 7.58% | 8 | 8.89% |
pre-git | pre-git | 100 | 6.31% | 2 | 2.22% |
ido schimmel | ido schimmel | 95 | 6.00% | 2 | 2.22% |
linus torvalds | linus torvalds | 70 | 4.42% | 2 | 2.22% |
jouni malinen | jouni malinen | 61 | 3.85% | 1 | 1.11% |
eric w. biederman | eric w. biederman | 52 | 3.28% | 3 | 3.33% |
jiri pirko | jiri pirko | 51 | 3.22% | 3 | 3.33% |
toshiaki makita | toshiaki makita | 42 | 2.65% | 4 | 4.44% |
eric dumazet | eric dumazet | 33 | 2.08% | 2 | 2.22% |
bart de schuymer | bart de schuymer | 27 | 1.70% | 3 | 3.33% |
pavel emelianov | pavel emelianov | 22 | 1.39% | 2 | 2.22% |
florian westphal | florian westphal | 19 | 1.20% | 1 | 1.11% |
david s. miller | david s. miller | 16 | 1.01% | 3 | 3.33% |
linus lussing | linus lussing | 12 | 0.76% | 2 | 2.22% |
arnaldo carvalho de melo | arnaldo carvalho de melo | 9 | 0.57% | 1 | 1.11% |
pablo neira ayuso | pablo neira ayuso | 5 | 0.32% | 1 | 1.11% |
arnd bergmann | arnd bergmann | 5 | 0.32% | 1 | 1.11% |
tejun heo | tejun heo | 3 | 0.19% | 1 | 1.11% |
jan engelhardt | jan engelhardt | 3 | 0.19% | 1 | 1.11% |
kris katterjohn | kris katterjohn | 3 | 0.19% | 1 | 1.11% |
paul gortmaker | paul gortmaker | 3 | 0.19% | 1 | 1.11% |
simon horman | simon horman | 3 | 0.19% | 1 | 1.11% |
americo wang | americo wang | 2 | 0.13% | 1 | 1.11% |
adrian bunk | adrian bunk | 1 | 0.06% | 1 | 1.11% |
ben hutchings | ben hutchings | 1 | 0.06% | 1 | 1.11% |
michael braun | michael braun | 1 | 0.06% | 1 | 1.11% |
hideaki yoshifuji | hideaki yoshifuji | 1 | 0.06% | 1 | 1.11% |
joe perches | joe perches | 1 | 0.06% | 1 | 1.11% |
li rongqing | li rongqing | 1 | 0.06% | 1 | 1.11% |
| Total | 1584 | 100.00% | 90 | 100.00% |
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.