cregit-Linux how code gets into the kernel

Release 4.15 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"
#include "br_private_tunnel.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) { br_drop_fake_rtable(skb); return netif_receive_skb(skb); }

Contributors

PersonTokensPropCommitsCommitProp
Eric W. Biedermann2784.38%266.67%
Florian Westphal515.62%133.33%
Total32100.00%3100.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, NULL, 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

PersonTokensPropCommitsCommitProp
Vlad Yasevich6332.81%316.67%
Nikolay Aleksandrov2714.06%316.67%
Linus Torvalds (pre-git)2412.50%15.56%
Stephen Hemminger2110.94%15.56%
Eric Dumazet168.33%15.56%
Linus Torvalds136.77%15.56%
Herbert Xu84.17%15.56%
Pavel Emelyanov84.17%15.56%
Eric W. Biedermann63.12%211.11%
Roopa Prabhu21.04%15.56%
David S. Miller21.04%15.56%
Li RongQing10.52%15.56%
Jan Engelhardt10.52%15.56%
Total192100.00%18100.00%

/* 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) || skb->protocol == htons(ETH_P_RARP))) { br_do_proxy_suppress_arp(skb, br, vid, p); } else if (IS_ENABLED(CONFIG_IPV6) && skb->protocol == htons(ETH_P_IPV6) && br->neigh_suppress_enabled && pskb_may_pull(skb, sizeof(struct ipv6hdr) + sizeof(struct nd_msg)) && ipv6_hdr(skb)->nexthdr == IPPROTO_ICMPV6) { struct nd_msg *msg, _msg; msg = br_is_nd_neigh_msg(skb, &_msg); if (msg) br_do_suppress_nd(skb, br, vid, p, msg); } 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->host_joined) || 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; }

Contributors

PersonTokensPropCommitsCommitProp
Nikolay Aleksandrov16327.77%1020.00%
Roopa Prabhu9716.52%24.00%
Herbert Xu9015.33%612.00%
Stephen Hemminger8614.65%714.00%
Linus Torvalds (pre-git)437.33%24.00%
Vlad Yasevich345.79%612.00%
Kyeyoon Park172.90%12.00%
Linus Lüssing122.04%24.00%
Linus Torvalds81.36%12.00%
Ido Schimmel71.19%12.00%
Arnd Bergmann50.85%12.00%
Eric W. Biedermann50.85%12.00%
David S. Miller50.85%12.00%
Pavel Emelyanov30.51%12.00%
Toshiaki Makita30.51%24.00%
Jouni Malinen30.51%12.00%
Américo Wang20.34%12.00%
Hideaki Yoshifuji / 吉藤英明10.17%12.00%
Andrew Lunn10.17%12.00%
Jiri Pirko10.17%12.00%
Michael Braun10.17%12.00%
Total587100.00%50100.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 Hemminger3552.24%114.29%
Vlad Yasevich1522.39%228.57%
Toshiaki Makita1319.40%228.57%
Ido Schimmel34.48%114.29%
Jiri 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 Schimmel3762.71%133.33%
Florian Westphal1830.51%133.33%
Stephen 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 (p->flags & BR_VLAN_TUNNEL) { if (br_handle_ingress_vlan_tunnel(skb, p, nbp_vlan_group_rcu(p))) goto drop; } 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 */ fwd_mask |= p->group_fwd_mask; 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

PersonTokensPropCommitsCommitProp
Stephen Hemminger11226.35%1231.58%
Ido Schimmel5412.71%25.26%
Jiri Pirko4911.53%37.89%
Linus Torvalds4510.59%25.26%
Bart De Schuymer276.35%37.89%
Roopa Prabhu276.35%12.63%
Toshiaki Makita266.12%12.63%
Herbert Xu163.76%12.63%
Eric W. Biedermann143.29%12.63%
Pavel Emelyanov112.59%12.63%
Arnaldo Carvalho de Melo92.12%12.63%
Linus Torvalds (pre-git)81.88%12.63%
David S. Miller81.88%25.26%
Nikolay Aleksandrov61.41%12.63%
Eric Dumazet51.18%12.63%
Simon Horman30.71%12.63%
Jan Engelhardt20.47%12.63%
Ben Hutchings10.24%12.63%
Florian Westphal10.24%12.63%
Joe Perches10.24%12.63%
Total425100.00%38100.00%


Overall Contributors

PersonTokensPropCommitsCommitProp
Stephen Hemminger25918.29%2020.20%
Nikolay Aleksandrov19613.84%1313.13%
Roopa Prabhu1299.11%33.03%
Vlad Yasevich1158.12%88.08%
Herbert Xu1148.05%77.07%
Ido Schimmel1027.20%33.03%
Linus Torvalds (pre-git)876.14%22.02%
Linus Torvalds694.87%22.02%
Eric W. Biedermann523.67%33.03%
Jiri Pirko513.60%33.03%
Toshiaki Makita422.97%44.04%
Eric Dumazet332.33%22.02%
Bart De Schuymer271.91%33.03%
Florian Westphal241.69%22.02%
Kyeyoon Park231.62%11.01%
Pavel Emelyanov221.55%22.02%
David S. Miller161.13%33.03%
Linus Lüssing120.85%22.02%
Arnaldo Carvalho de Melo90.64%11.01%
Pablo Neira Ayuso50.35%11.01%
Arnd Bergmann50.35%11.01%
Simon Horman30.21%11.01%
Jouni Malinen30.21%11.01%
Jan Engelhardt30.21%11.01%
Tejun Heo30.21%11.01%
Paul Gortmaker30.21%11.01%
Américo Wang20.14%11.01%
Joe Perches10.07%11.01%
Andrew Lunn10.07%11.01%
Michael Braun10.07%11.01%
Adrian Bunk10.07%11.01%
Li RongQing10.07%11.01%
Hideaki Yoshifuji / 吉藤英明10.07%11.01%
Ben Hutchings10.07%11.01%
Total1416100.00%99100.00%
Directory: net/bridge
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.