--- zzzz-none-000/linux-4.1.38/net/bridge/br_input.c 2017-01-18 18:48:06.000000000 +0000 +++ bcm63-7582-715/linux-4.1.38/net/bridge/br_input.c 2020-11-25 10:06:48.000000000 +0000 @@ -21,6 +21,22 @@ #include #include #include "br_private.h" +#if defined(CONFIG_BCM_KF_BLOG) && defined(CONFIG_BLOG) +#include +#endif +#if defined(CONFIG_BCM_KF_WL) +#if defined(PKTC) +//#include +//#include +#include + +unsigned long (*wl_pktc_req_hook)(int req_id, unsigned long param0, unsigned long param1, unsigned long param2) = NULL; +EXPORT_SYMBOL(wl_pktc_req_hook); +unsigned long (*dhd_pktc_req_hook)(int req_id, unsigned long param0, unsigned long param1, unsigned long param2) = NULL; +EXPORT_SYMBOL(dhd_pktc_req_hook); +#endif /* PKTC */ +#include +#endif /* Hook for brouter */ br_should_route_hook_t __rcu *br_should_route_hook __read_mostly; @@ -33,6 +49,16 @@ struct pcpu_sw_netstats *brstats = this_cpu_ptr(br->stats); struct net_port_vlans *pv; +#if defined(CONFIG_BCM_KF_BLOG) && defined(CONFIG_BLOG) + blog_lock(); + blog_link(IF_DEVICE, blog_ptr(skb), (void*)br->dev, DIR_RX, skb->len); + blog_unlock(); + + /* Gather general RX statistics */ + brdev->stats.rx_packets++; + brdev->stats.rx_bytes += skb->len; +#endif + u64_stats_update_begin(&brstats->syncp); brstats->rx_packets++; brstats->rx_bytes += skb->len; @@ -137,6 +163,26 @@ if (!br_allowed_ingress(p->br, nbp_get_vlan_info(p), skb, &vid)) goto out; +#if defined(CONFIG_BCM_KF_VLAN_AGGREGATION) && defined(CONFIG_BCM_VLAN_AGGREGATION) +#if defined(CONFIG_BCM_KF_VLAN) && (defined(CONFIG_BCM_VLAN) || defined(CONFIG_BCM_VLAN_MODULE)) + if (skb->vlan_count) + vid = (skb->vlan_header[0] >> 16) & VLAN_VID_MASK; + else +#endif /* CONFIG_BCM_VLAN) */ + /* + * dev.c/__netif_receive_skb(): if proto == ETH_P_8021Q + * call vlan_untag() to remove tag and save vid in skb->vlan_tci + */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0)) + if (vlan_tx_tag_present(skb)) +#else + if (skb_vlan_tag_present(skb)) +#endif + vid = skb->vlan_tci & VLAN_VID_MASK; + else if ( vlan_eth_hdr(skb)->h_vlan_proto == htons(ETH_P_8021Q) ) + vid = ntohs(vlan_eth_hdr(skb)->h_vlan_TCI) & VLAN_VID_MASK; +#endif + /* insert into forwarding database after filtering to avoid spoofing */ br = p->br; if (p->flags & BR_LEARNING) @@ -146,10 +192,18 @@ br_multicast_rcv(br, p, skb, vid)) goto drop; +#if defined(CONFIG_BCM_KF_WL) + if ((p->state == BR_STATE_LEARNING) && + (skb->protocol != htons(0x886c) /*ETHER_TYPE_BRCM*/) && + (skb->protocol != htons(0x888e) /*ETHER_TYPE_802_1X*/) && + (skb->protocol != htons(0x88c7) /*ETHER_TYPE_802_1X_PREAUTH*/)) +#else if (p->state == BR_STATE_LEARNING) +#endif goto drop; BR_INPUT_SKB_CB(skb)->brdev = br->dev; + BR_INPUT_SKB_CB(skb)->src_port_isolated = !!(p->flags & BR_ISOLATED); /* The packet skb2 goes to the local host (NULL to skip). */ skb2 = NULL; @@ -162,8 +216,33 @@ if (IS_ENABLED(CONFIG_INET) && skb->protocol == htons(ETH_P_ARP)) br_do_proxy_arp(skb, br, vid, p); +#if (defined(CONFIG_BCM_MCAST) || defined(CONFIG_BCM_MCAST_MODULE)) && defined(CONFIG_BCM_KF_MCAST) + if ( br_bcm_mcast_receive != NULL ) + { + int rv = br_bcm_mcast_receive(br->dev->ifindex, skb, 0); + if ( rv < 0 ) + { + /* there was an error with the packet */ + goto drop; + } + else if ( rv > 0 ) + { + /* the packet was consumed */ + goto out; + } + /* continue */ + } +#endif + if (is_broadcast_ether_addr(dest)) { +#if defined(CONFIG_BCM_KF_EXTSTATS) + { + br->dev->stats.rx_broadcast_packets++; +#endif skb2 = skb; +#if defined(CONFIG_BCM_KF_EXTSTATS) + } +#endif unicast = false; } else if (is_multicast_ether_addr(dest)) { mdst = br_mdb_get(br, skb, vid); @@ -181,18 +260,177 @@ unicast = false; br->dev->stats.multicast++; +#if defined(CONFIG_BCM_KF_EXTSTATS) + br->dev->stats.rx_multicast_bytes += skb2->len; +#endif +#if !(defined(CONFIG_BCM_KF_BLOG) && defined(CONFIG_BLOG)) } 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; } +#else + } else { + struct net_bridge_fdb_entry *src; + + dst = __br_fdb_get(br, dest, vid); + src = __br_fdb_get(br, eth_hdr(skb)->h_source, vid); + blog_lock(); + if (src) + blog_link(BRIDGEFDB, blog_ptr(skb), (void*)src, BLOG_PARAM1_SRCFDB, 0); + + if (dst) + blog_link(BRIDGEFDB, blog_ptr(skb), (void*)dst, BLOG_PARAM1_DSTFDB, 0); + + blog_unlock(); + +#if defined(PKTC) + /* wlan pktc */ + if ((dst != NULL) && (dst->dst != NULL) && (!dst->is_local)) { +#if defined(CONFIG_BCM_KF_WL) + u8 from_wl_to_switch=0, from_switch_to_wl=0, from_wlan_to_wlan=0; + struct net_device *root_dst_dev_p = dst->dst->dev; + BlogPhy_t srcPhyType, dstPhyType; + uint32_t chainIdx; + uint16_t dst_dev_has_vlan = 0; + uint32_t pktc_tx_enabled = wl_pktc_req_hook ? + wl_pktc_req_hook(PKTC_TBL_GET_TX_MODE, 0, 0, 0) : 0; + + src = __br_fdb_get(br, eth_hdr(skb)->h_source, vid); + if (unlikely(src == NULL) || unlikely(src->dst == NULL)) + goto next; + + srcPhyType = BLOG_GET_PHYTYPE(src->dst->dev->path.hw_port_type); + dstPhyType = BLOG_GET_PHYTYPE(dst->dst->dev->path.hw_port_type); + + + if ((srcPhyType == BLOG_WLANPHY) && + (dstPhyType == BLOG_ENETPHY)) { + from_wl_to_switch = 1; + while (!netdev_path_is_root(root_dst_dev_p) && + (root_dst_dev_p->priv_flags & IFF_BCM_VLAN)) { + root_dst_dev_p = netdev_path_next_dev(root_dst_dev_p); + } + } else if ((srcPhyType == BLOG_ENETPHY || srcPhyType == BLOG_XTMPHY || + srcPhyType == BLOG_EPONPHY || srcPhyType == BLOG_GPONPHY) && + (dstPhyType == BLOG_WLANPHY) && + pktc_tx_enabled) + { + from_switch_to_wl = 1; + } + +#if defined (CONFIG_BCM_DHD_RUNNER) && defined (CONFIG_BCM_WIFI_FORWARDING_DRV_MODULE) + else if((srcPhyType == BLOG_WLANPHY) && (dstPhyType == BLOG_WLANPHY)) + from_wlan_to_wlan = 1; +#endif +#if defined(CONFIG_BCM_KF_WANDEV) + + if ((dst->dst->dev->priv_flags & IFF_BCM_VLAN)) + { + int len = strlen(dst->dst->dev->name); + dst_dev_has_vlan = 1; + + /* Check dev is default LAN side VLAN (for ex:eth1.0 or eth2.0) + that doesn't add/remove VLAN tag. So still create PKTC for it. */ + + if ((!(dst->dst->dev->priv_flags & IFF_WANDEV)) && (len > 3)) + { + if( (dst->dst->dev->name[len-2] == '.') && (dst->dst->dev->name[len-1] == '0') ) + { + dst_dev_has_vlan = 0; + } + } +#if 0 + printk(" %s:%d Dev %s, has_vlan:%d \n",__FUNCTION__,__LINE__,dst->dst->dev->name,dst_dev_has_vlan); +#endif + } + if ((from_wl_to_switch || from_switch_to_wl || from_wlan_to_wlan) && + !(dst->dst->dev->priv_flags & IFF_WANDEV) && + !(dst_dev_has_vlan) && + netdev_path_is_root(root_dst_dev_p)) { + /* Also check for non-WAN cases. + * For the Rx direction, VLAN cases are allowed as long + * as the packets are untagged. + * + * Tagged packets are not forwarded through the chaining + * path by WLAN driver. Tagged packets go through the + * flowcache path. + * see wlc_sendup_chain() function for reference. + * + * For the Tx direction, there are no VLAN interfaces + * created on wl device when LAN_VLAN flag is enabled + * in the build. + * + * The netdev_path_is_root() check makes sure that we + * are always transmitting to a root device */ + + /* Update chaining table for DHD on the wl to switch direction only */ + if ((from_wl_to_switch) && (dhd_pktc_req_hook != NULL)) { + dhd_pktc_req_hook(PKTC_TBL_UPDATE, + (unsigned long)&(dst->addr.addr[0]), + (unsigned long)root_dst_dev_p, 0); + } + + /* Update chaining table for WL (NIC driver) */ + chainIdx = wl_pktc_req_hook ? + wl_pktc_req_hook(PKTC_TBL_UPDATE, + (unsigned long)&(dst->addr.addr[0]), + (unsigned long)root_dst_dev_p, 0) : PKTC_INVALID_CHAIN_IDX; + if (chainIdx != PKTC_INVALID_CHAIN_IDX) { + /* Update chainIdx in blog + * chainEntry->tx_dev will always be NOT + * NULL as we just added that above */ + if (skb->blog_p != NULL) + { + if (from_switch_to_wl || from_wlan_to_wlan) + { + skb->blog_p->wfd.nic_ucast.is_tx_hw_acc_en = 1; + + /* in case of flow from WLAN to WLAN the flow will + * be open in Runner only if is_rx_hw_acc_en in DHD + */ + if(from_wlan_to_wlan && (0 == skb->blog_p->rnr.is_rx_hw_acc_en)) + skb->blog_p->wfd.nic_ucast.is_tx_hw_acc_en = 0; + + skb->blog_p->wfd.nic_ucast.is_chain = 1; + skb->blog_p->wfd.nic_ucast.wfd_idx = ((chainIdx & PKTC_WFD_IDX_BITMASK) >> PKTC_WFD_IDX_BITPOS); + skb->blog_p->wfd.nic_ucast.chain_idx = chainIdx; + } +#if 0 + printk("Added ChainEntryIdx 0x%x Dev %s blogSrcAddr 0x%x blogDstAddr 0x%x DstMac %x:%x:%x:%x:%x:%x " + "wfd_q %d wl_metadata %d wl 0x%x\n", + chainIdx, dst->dst->dev->name, skb->blog_p->rx.tuple.saddr, skb->blog_p->rx.tuple.daddr, + dst->addr.addr[0], dst->addr.addr[1], dst->addr.addr[2], dst->addr.addr[3], dst->addr.addr[4], + dst->addr.addr[5], skb->blog_p->wfd_queue, skb->blog_p->wl_metadata, skb->blog_p->wl); +#endif + } + } + } +#endif /* CONFIG_BCM_KF_WANDEV */ +#endif + } +next: +#endif /* PKTC */ + if ((dst != NULL) && dst->is_local) { + skb2 = skb; + /* Do not forward the packet since it's local. */ + skb = NULL; + } + } +#endif if (skb) { if (dst) { dst->used = jiffies; br_forward(dst->dst, skb, skb2); } else +#if defined(CONFIG_BCM_KF_FBOND) && (defined(CONFIG_BCM_FBOND) || defined(CONFIG_BCM_FBOND_MODULE)) + if (BR_STATE_BLOCKING == p->state) + /* prevent flooding unknown unicast from blocked port */ + goto drop; + else +#endif br_flood_forward(br, skb, skb2, unicast); } @@ -242,6 +480,13 @@ p = br_port_get_rcu(skb->dev); +#if defined(CONFIG_BCM_KF_WANDEV) + if (!p) + { + kfree_skb(skb); + return RX_HANDLER_CONSUMED; + } +#endif if (unlikely(is_link_local_ether_addr(dest))) { u16 fwd_mask = p->br->group_fwd_mask_required; @@ -288,8 +533,54 @@ } forward: +#if defined(CONFIG_BCM_KF_IEEE1905) && defined(CONFIG_BCM_IEEE1905) + /* allow broute to forward packets to the stack in any STP state */ + rhook = rcu_dereference(br_should_route_hook); + if (rhook) { + if ((*rhook)(skb)) { + *pskb = skb; + if ((skb->protocol == htons(0x893a)) || + (skb->protocol == htons(0x8912)) || + (skb->protocol == htons(0x88e1))) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) + br_handle_local_finish(NULL, skb); +#else + br_handle_local_finish(skb); +#endif + + return RX_HANDLER_PASS; + } else if (skb->protocol == htons(0x893a) && + (skb->pkt_type == PACKET_MULTICAST)) + /* do not bridge multicast 1905 packets when 1905 is compiled */ + goto drop; + + dest = eth_hdr(skb)->h_dest; + } +#endif + +#if defined(CONFIG_BCM_KF_WL) + if (( (skb->protocol == htons(0x886c) /*ETHER_TYPE_BRCM*/) || + (skb->protocol == htons(0x888e) /*ETHER_TYPE_802_1X*/) || + (skb->protocol == htons(0x88c7) /*ETHER_TYPE_802_1X_PREAUTH*/) ) && + (p->state != BR_STATE_FORWARDING) && (p->state != BR_STATE_DISABLED)) { + /* force to forward brcm_type event packet */ + NF_HOOK(NFPROTO_BRIDGE, NF_BR_PRE_ROUTING, NULL, skb, skb->dev, NULL, + br_handle_frame_finish); + return RX_HANDLER_CONSUMED; + } +#endif + switch (p->state) { +#if defined(CONFIG_BCM_KF_FBOND) && (defined(CONFIG_BCM_FBOND) || defined(CONFIG_BCM_FBOND_MODULE)) + case BR_STATE_BLOCKING: + /* if this is unicast let it through even if the port is blocked + it will be dropped later if a destination is not found to + prevent flooding unicast from a blocked port */ + if (is_multicast_ether_addr(dest)) + goto drop; +#endif case BR_STATE_FORWARDING: +#if !defined(CONFIG_BCM_KF_IEEE1905) || !defined(CONFIG_BCM_IEEE1905) rhook = rcu_dereference(br_should_route_hook); if (rhook) { if ((*rhook)(skb)) { @@ -298,6 +589,7 @@ } dest = eth_hdr(skb)->h_dest; } +#endif /* fall through */ case BR_STATE_LEARNING: if (ether_addr_equal(p->br->dev->dev_addr, dest))