cregit-Linux how code gets into the kernel

Release 4.7 net/bridge/br_input.c

Directory: net/bridge
/*
 *      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

PersonTokensPropCommitsCommitProp
eric w. biedermaneric w. biederman27100.00%2100.00%
Total27100.00%2100.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; return NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_IN, dev_net(indev), NULL, skb, indev, NULL, br_netif_receive_skb); }

Contributors

PersonTokensPropCommitsCommitProp
vlad yasevichvlad yasevich6336.42%318.75%
pre-gitpre-git2413.87%16.25%
stephen hemmingerstephen hemminger2112.14%16.25%
eric dumazeteric dumazet169.25%16.25%
linus torvaldslinus torvalds137.51%16.25%
nikolay aleksandrovnikolay aleksandrov105.78%212.50%
pavel emelianovpavel emelianov84.62%16.25%
herbert xuherbert xu84.62%16.25%
eric w. biedermaneric w. biederman63.47%212.50%
david s. millerdavid s. miller21.16%16.25%
li rongqingli rongqing10.58%16.25%
jan engelhardtjan engelhardt10.58%16.25%
Total173100.00%16100.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) return; if (!pskb_may_pull(skb, arp_hdr_len(dev))) { dev->stats.tx_dropped++; 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

PersonTokensPropCommitsCommitProp
kyeyoon parkkyeyoon park29085.04%150.00%
jouni malinenjouni malinen5114.96%150.00%
Total341100.00%2100.00%

/* note: already called with rcu_read_lock */
int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb) { const unsigned char *dest = eth_hdr(skb)->h_dest; struct net_bridge_port *p = br_port_get_rcu(skb->dev); struct net_bridge *br; struct net_bridge_fdb_entry *dst; struct net_bridge_mdb_entry *mdst; struct sk_buff *skb2; bool unicast = true; 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; /* The packet skb2 goes to the local host (NULL to skip). */ skb2 = NULL; if (br->dev->flags & IFF_PROMISC) skb2 = skb; dst = NULL; 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)) { skb2 = skb; 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)) skb2 = skb; br_multicast_forward(mdst, skb, skb2); skb = NULL; if (!skb2) goto out; } else skb2 = skb; unicast = false; br->dev->stats.multicast++; } else if ((dst = __br_fdb_get(br, dest, vid)) && dst->is_local) { skb2 = skb; /* Do not forward the packet since it's local. */ skb = NULL; } if (skb) { if (dst) { dst->used = jiffies; br_forward(dst->dst, skb, skb2); } else br_flood_forward(br, skb, skb2, unicast); } if (skb2) return br_pass_frame_up(skb2); out: return 0; drop: kfree_skb(skb); goto out; }

Contributors

PersonTokensPropCommitsCommitProp
herbert xuherbert xu15633.91%614.29%
stephen hemmingerstephen hemminger9220.00%819.05%
pre-gitpre-git7215.65%24.76%
vlad yasevichvlad yasevich4910.65%614.29%
kyeyoon parkkyeyoon park183.91%12.38%
linus lussinglinus lussing122.61%24.76%
jouni malinenjouni malinen102.17%12.38%
linus torvaldslinus torvalds102.17%24.76%
nikolay aleksandrovnikolay aleksandrov81.74%24.76%
arnd bergmannarnd bergmann51.09%12.38%
eric w. biedermaneric w. biederman51.09%12.38%
david s. millerdavid s. miller51.09%12.38%
kris katterjohnkris katterjohn30.65%12.38%
pavel emelianovpavel emelianov30.65%12.38%
toshiaki makitatoshiaki makita30.65%24.76%
arnaldo carvalho de meloarnaldo carvalho de melo30.65%12.38%
americo wangamerico wang20.43%12.38%
michael braunmichael braun20.43%12.38%
jiri pirkojiri pirko10.22%12.38%
hideaki yoshifujihideaki yoshifuji10.22%12.38%
Total460100.00%42100.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

PersonTokensPropCommitsCommitProp
stephen hemmingerstephen hemminger3552.24%114.29%
vlad yasevichvlad yasevich1522.39%228.57%
toshiaki makitatoshiaki makita1319.40%228.57%
ido schimmelido schimmel34.48%114.29%
jiri pirkojiri pirko11.49%114.29%
Total67100.00%7100.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

PersonTokensPropCommitsCommitProp
ido schimmelido schimmel3762.71%133.33%
florian westphalflorian westphal1830.51%133.33%
stephen hemmingerstephen hemminger46.78%133.33%
Total59100.00%3100.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; 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

PersonTokensPropCommitsCommitProp
stephen hemmingerstephen hemminger11231.91%1234.29%
jiri pirkojiri pirko4913.96%38.57%
linus torvaldslinus torvalds4512.82%25.71%
bart de schuymerbart de schuymer277.69%38.57%
toshiaki makitatoshiaki makita267.41%12.86%
herbert xuherbert xu164.56%12.86%
eric w. biedermaneric w. biederman143.99%12.86%
ido schimmelido schimmel133.70%12.86%
pavel emelianovpavel emelianov113.13%12.86%
arnaldo carvalho de meloarnaldo carvalho de melo92.56%12.86%
david s. millerdavid s. miller82.28%25.71%
pre-gitpre-git82.28%12.86%
eric dumazeteric dumazet51.42%12.86%
simon hormansimon horman30.85%12.86%
jan engelhardtjan engelhardt20.57%12.86%
joe perchesjoe perches10.28%12.86%
florian westphalflorian westphal10.28%12.86%
ben hutchingsben hutchings10.28%12.86%
Total351100.00%35100.00%


Overall Contributors

PersonTokensPropCommitsCommitProp
kyeyoon parkkyeyoon park31420.54%11.20%
stephen hemmingerstephen hemminger26517.33%2024.10%
herbert xuherbert xu18011.77%78.43%
vlad yasevichvlad yasevich1308.50%89.64%
pre-gitpre-git1167.59%22.41%
linus torvaldslinus torvalds714.64%22.41%
jouni malinenjouni malinen613.99%11.20%
ido schimmelido schimmel543.53%11.20%
eric w. biedermaneric w. biederman523.40%33.61%
jiri pirkojiri pirko513.34%33.61%
toshiaki makitatoshiaki makita422.75%44.82%
eric dumazeteric dumazet332.16%22.41%
bart de schuymerbart de schuymer271.77%33.61%
pavel emelianovpavel emelianov221.44%22.41%
florian westphalflorian westphal191.24%11.20%
nikolay aleksandrovnikolay aleksandrov181.18%33.61%
david s. millerdavid s. miller161.05%33.61%
linus lussinglinus lussing120.78%22.41%
arnaldo carvalho de meloarnaldo carvalho de melo120.78%11.20%
arnd bergmannarnd bergmann50.33%11.20%
pablo neira ayusopablo neira ayuso50.33%11.20%
kris katterjohnkris katterjohn30.20%11.20%
paul gortmakerpaul gortmaker30.20%11.20%
tejun heotejun heo30.20%11.20%
jan engelhardtjan engelhardt30.20%11.20%
simon hormansimon horman30.20%11.20%
americo wangamerico wang20.13%11.20%
michael braunmichael braun20.13%11.20%
adrian bunkadrian bunk10.07%11.20%
ben hutchingsben hutchings10.07%11.20%
li rongqingli rongqing10.07%11.20%
hideaki yoshifujihideaki yoshifuji10.07%11.20%
joe perchesjoe perches10.07%11.20%
Total1529100.00%83100.00%
Directory: net/bridge
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
{% endraw %}