diff --git a/target/linux/ipq806x/patches-5.15/999-300-qca-mcs-support.patch b/target/linux/ipq806x/patches-5.15/999-300-qca-mcs-support.patch new file mode 100644 index 0000000000..6f05369766 --- /dev/null +++ b/target/linux/ipq806x/patches-5.15/999-300-qca-mcs-support.patch @@ -0,0 +1,932 @@ +--- a/include/linux/if_bridge.h ++++ b/include/linux/if_bridge.h +@@ -235,4 +235,17 @@ extern br_get_dst_hook_t __rcu *br_get_d + extern struct net_device *br_fdb_bridge_dev_get_and_hold(struct net_bridge *br); + /* QCA NSS bridge-mgr support - End */ + ++/* QCA qca-mcs support - Start */ ++typedef struct net_bridge_port *br_get_dst_hook_t(const struct net_bridge_port *src, ++ struct sk_buff **skb); ++extern br_get_dst_hook_t __rcu *br_get_dst_hook; ++ ++typedef int (br_multicast_handle_hook_t)(const struct net_bridge_port *src, ++ struct sk_buff *skb); ++extern br_multicast_handle_hook_t __rcu *br_multicast_handle_hook; ++ ++typedef void (br_notify_hook_t)(int group, int event, const void *ptr); ++extern br_notify_hook_t __rcu *br_notify_hook; ++/* QCA qca-mcs support - End */ ++ + #endif +--- a/net/bridge/br_fdb.c ++++ b/net/bridge/br_fdb.c +@@ -186,6 +186,7 @@ struct net_bridge_fdb_entry *br_fdb_find + { + return fdb_find_rcu(&br->fdb_hash_tbl, addr, vid); + } ++EXPORT_SYMBOL_GPL(br_fdb_find_rcu); /* QCA qca-mcs support */ + + /* When a static FDB entry is added, the mac address from the entry is + * added to the bridge private HW address list and all required ports +@@ -892,6 +893,7 @@ static void fdb_notify(struct net_bridge + kfree_skb(skb); + goto errout; + } ++ __br_notify(RTNLGRP_NEIGH, type, fdb); /* QCA qca-mcs support */ + rtnl_notify(skb, net, 0, RTNLGRP_NEIGH, NULL, GFP_ATOMIC); + return; + errout: +--- a/net/bridge/br_private.h ++++ b/net/bridge/br_private.h +@@ -853,6 +853,7 @@ void br_manage_promisc(struct net_bridge + int nbp_backup_change(struct net_bridge_port *p, struct net_device *backup_dev); + + /* br_input.c */ ++int br_pass_frame_up(struct sk_buff *skb); /* QCA qca-mcs support */ + int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb); + rx_handler_func_t *br_get_rx_handler(const struct net_device *dev); + +@@ -2125,4 +2126,14 @@ struct nd_msg *br_is_nd_neigh_msg(struct + #define __br_get(__hook, __default, __args ...) \ + (__hook ? (__hook(__args)) : (__default)) + /* QCA NSS ECM support - End */ ++ ++/* QCA qca-mcs support - Start */ ++static inline void __br_notify(int group, int type, const void *data) ++{ ++ br_notify_hook_t *notify_hook = rcu_dereference(br_notify_hook); ++ ++ if (notify_hook) ++ notify_hook(group, type, data); ++} ++/* QCA qca-mcs support - End */ + #endif +--- a/net/bridge/br_netlink.c ++++ b/net/bridge/br_netlink.c +@@ -609,6 +609,7 @@ void br_info_notify(int event, const str + kfree_skb(skb); + goto errout; + } ++ __br_notify(RTNLGRP_LINK, event, port); /* QCA qca-mcs support */ + rtnl_notify(skb, net, 0, RTNLGRP_LINK, NULL, GFP_ATOMIC); + return; + errout: +--- a/net/bridge/br.c ++++ b/net/bridge/br.c +@@ -463,6 +463,12 @@ static void __exit br_deinit(void) + br_fdb_fini(); + } + ++/* QCA qca-mcs support - Start */ ++/* Hook for bridge event notifications */ ++br_notify_hook_t __rcu *br_notify_hook __read_mostly; ++EXPORT_SYMBOL_GPL(br_notify_hook); ++/* QCA qca-mcs support - End */ ++ + module_init(br_init) + module_exit(br_deinit) + MODULE_LICENSE("GPL"); +--- a/net/bridge/br_device.c ++++ b/net/bridge/br_device.c +@@ -82,6 +82,12 @@ netdev_tx_t br_dev_xmit(struct sk_buff * + if (is_broadcast_ether_addr(dest)) { + br_flood(br, skb, BR_PKT_BROADCAST, false, true); + } else if (is_multicast_ether_addr(dest)) { ++ /* QCA qca-mcs support - Start */ ++ br_multicast_handle_hook_t *multicast_handle_hook = rcu_dereference(br_multicast_handle_hook); ++ if (!__br_get(multicast_handle_hook, true, NULL, skb)) ++ goto out; ++ /* QCA qca-mcs support - End */ ++ + if (unlikely(netpoll_tx_running(dev))) { + br_flood(br, skb, BR_PKT_MULTICAST, false, true); + goto out; +--- a/net/bridge/br_input.c ++++ b/net/bridge/br_input.c +@@ -24,6 +24,16 @@ + #include "br_private_tunnel.h" + #include "br_private_offload.h" + ++/* QCA qca-mcs support - Start */ ++/* Hook for external Multicast handler */ ++br_multicast_handle_hook_t __rcu *br_multicast_handle_hook __read_mostly; ++EXPORT_SYMBOL_GPL(br_multicast_handle_hook); ++ ++/* Hook for external forwarding logic */ ++br_get_dst_hook_t __rcu *br_get_dst_hook __read_mostly; ++EXPORT_SYMBOL_GPL(br_get_dst_hook); ++/* QCA qca-mcs support - End */ ++ + static int + br_netif_receive_skb(struct net *net, struct sock *sk, struct sk_buff *skb) + { +@@ -31,7 +41,7 @@ br_netif_receive_skb(struct net *net, st + return netif_receive_skb(skb); + } + +-static int br_pass_frame_up(struct sk_buff *skb) ++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); +@@ -70,6 +80,7 @@ static int br_pass_frame_up(struct sk_bu + dev_net(indev), NULL, skb, indev, NULL, + br_netif_receive_skb); + } ++EXPORT_SYMBOL_GPL(br_pass_frame_up); /* QCA qca-mcs support */ + + /* note: already called with rcu_read_lock */ + int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb) +@@ -85,6 +96,11 @@ int br_handle_frame_finish(struct net *n + struct net_bridge *br; + u16 vid = 0; + u8 state; ++ /* QCA qca-mcs support - Start */ ++ br_multicast_handle_hook_t *multicast_handle_hook; ++ struct net_bridge_port *pdst = NULL; ++ br_get_dst_hook_t *get_dst_hook = rcu_dereference(br_get_dst_hook); ++ /* QCA qca-mcs support - End */ + + if (!p || p->state == BR_STATE_DISABLED) + goto drop; +@@ -141,6 +157,11 @@ int br_handle_frame_finish(struct net *n + + switch (pkt_type) { + case BR_PKT_MULTICAST: ++ /* QCA qca-mcs support - Start */ ++ multicast_handle_hook = rcu_dereference(br_multicast_handle_hook); ++ if (!__br_get(multicast_handle_hook, true, p, skb)) ++ goto out; ++ /* QCA qca-mcs support - End */ + mdst = br_mdb_get(brmctx, skb, vid); + if ((mdst || BR_INPUT_SKB_CB_MROUTERS_ONLY(skb)) && + br_multicast_querier_exists(brmctx, eth_hdr(skb), mdst)) { +@@ -156,8 +177,15 @@ int br_handle_frame_finish(struct net *n + } + break; + case BR_PKT_UNICAST: +- dst = br_fdb_find_rcu(br, eth_hdr(skb)->h_dest, vid); +- break; ++ /* QCA qca-mcs support - Start */ ++ pdst = __br_get(get_dst_hook, NULL, p, &skb); ++ if (pdst) { ++ if (!skb) ++ goto out; ++ } else { ++ /* QCA qca-mcs support - End */ ++ dst = br_fdb_find_rcu(br, eth_hdr(skb)->h_dest, vid); ++ } + default: + break; + } +@@ -172,13 +200,20 @@ int br_handle_frame_finish(struct net *n + dst->used = now; + br_forward(dst->dst, skb, local_rcv, false); + } else { ++ /* QCA qca-mcs support - Start */ ++ if (pdst) { ++ br_forward(pdst, skb, local_rcv, false); ++ goto out1; ++ } ++ /* QCA qca-mcs support - End */ ++ + br_offload_skb_disable(skb); + if (!mcast_hit) + br_flood(br, skb, pkt_type, local_rcv, false); + else + br_multicast_flood(mdst, skb, brmctx, local_rcv, false); + } +- ++out1: /* QCA qca-mcs support */ + if (local_rcv) + return br_pass_frame_up(skb); + +--- a/include/linux/mroute.h ++++ b/include/linux/mroute.h +@@ -85,4 +85,44 @@ struct rtmsg; + int ipmr_get_route(struct net *net, struct sk_buff *skb, + __be32 saddr, __be32 daddr, + struct rtmsg *rtm, u32 portid); ++ ++/* QCA ECM qca-mcs support - Start */ ++#define IPMR_MFC_EVENT_UPDATE 1 ++#define IPMR_MFC_EVENT_DELETE 2 ++ ++/* ++ * Callback to registered modules in the event of updates to a multicast group ++ */ ++typedef void (*ipmr_mfc_event_offload_callback_t)(__be32 origin, __be32 group, ++ u32 max_dest_dev, ++ u32 dest_dev_idx[], ++ u8 op); ++ ++/* ++ * Register the callback used to inform offload modules when updates occur to ++ * MFC. The callback is registered by offload modules ++ */ ++extern bool ipmr_register_mfc_event_offload_callback( ++ ipmr_mfc_event_offload_callback_t mfc_offload_cb); ++ ++/* ++ * De-Register the callback used to inform offload modules when updates occur ++ * to MFC ++ */ ++extern void ipmr_unregister_mfc_event_offload_callback(void); ++ ++/* ++ * Find the destination interface list, given a multicast group and source ++ */ ++extern int ipmr_find_mfc_entry(struct net *net, __be32 origin, __be32 group, ++ u32 max_dst_cnt, u32 dest_dev[]); ++ ++/* ++ * Out-of-band multicast statistics update for flows that are offloaded from ++ * Linux ++ */ ++extern int ipmr_mfc_stats_update(struct net *net, __be32 origin, __be32 group, ++ u64 pkts_in, u64 bytes_in, ++ u64 pkts_out, u64 bytes_out); ++/* QCA ECM qca-mcs support - End */ + #endif +--- a/include/linux/mroute6.h ++++ b/include/linux/mroute6.h +@@ -110,4 +110,47 @@ static inline int ip6mr_sk_done(struct s + return 0; + } + #endif ++ ++/* QCA qca-mcs support - Start */ ++#define IP6MR_MFC_EVENT_UPDATE 1 ++#define IP6MR_MFC_EVENT_DELETE 2 ++ ++/* ++ * Callback to registered modules in the event of updates to a multicast group ++ */ ++typedef void (*ip6mr_mfc_event_offload_callback_t)(struct in6_addr *origin, ++ struct in6_addr *group, ++ u32 max_dest_dev, ++ u32 dest_dev_idx[], ++ uint8_t op); ++ ++/* ++ * Register the callback used to inform offload modules when updates occur ++ * to MFC. The callback is registered by offload modules ++ */ ++extern bool ip6mr_register_mfc_event_offload_callback( ++ ip6mr_mfc_event_offload_callback_t mfc_offload_cb); ++ ++/* ++ * De-Register the callback used to inform offload modules when updates occur ++ * to MFC ++ */ ++extern void ip6mr_unregister_mfc_event_offload_callback(void); ++ ++/* ++ * Find the destination interface list given a multicast group and source ++ */ ++extern int ip6mr_find_mfc_entry(struct net *net, struct in6_addr *origin, ++ struct in6_addr *group, u32 max_dst_cnt, ++ u32 dest_dev[]); ++ ++/* ++ * Out-of-band multicast statistics update for flows that are offloaded from ++ * Linux ++ */ ++extern int ip6mr_mfc_stats_update(struct net *net, struct in6_addr *origin, ++ struct in6_addr *group, uint64_t pkts_in, ++ uint64_t bytes_in, uint64_t pkts_out, ++ uint64_t bytes_out); ++/* QCA qca-mcs support - End */ + #endif +--- a/net/ipv4/ipmr.c ++++ b/net/ipv4/ipmr.c +@@ -108,6 +108,15 @@ static void igmpmsg_netlink_event(struct + static void mroute_clean_tables(struct mr_table *mrt, int flags); + static void ipmr_expire_process(struct timer_list *t); + ++/* QCA ECM qca-mcs support - Start */ ++/* spinlock for offload */ ++static DEFINE_SPINLOCK(lock); ++ ++static struct mfc_cache *ipmr_cache_find(struct mr_table *mrt, __be32 origin, ++ __be32 mcastgrp); ++static ipmr_mfc_event_offload_callback_t __rcu ipmr_mfc_event_offload_callback; ++/* QCA ECM qca-mcs support - End */ ++ + #ifdef CONFIG_IP_MROUTE_MULTIPLE_TABLES + #define ipmr_for_each_table(mrt, net) \ + list_for_each_entry_rcu(mrt, &net->ipv4.mr_tables, list, \ +@@ -222,6 +231,228 @@ static int ipmr_rule_fill(struct fib_rul + return 0; + } + ++/* QCA ECM qca-mcs support - Start */ ++/* ipmr_sync_entry_update() ++ * Call the registered offload callback to report an update to a multicast ++ * route entry. The callback receives the list of destination interfaces and ++ * the interface count ++ */ ++static void ipmr_sync_entry_update(struct mr_table *mrt, ++ struct mfc_cache *cache) ++{ ++ int vifi, dest_if_count = 0; ++ u32 dest_dev[MAXVIFS]; ++ __be32 origin; ++ __be32 group; ++ ipmr_mfc_event_offload_callback_t offload_update_cb_f; ++ ++ memset(dest_dev, 0, sizeof(dest_dev)); ++ ++ origin = cache->mfc_origin; ++ group = cache->mfc_mcastgrp; ++ ++ read_lock(&mrt_lock); ++ for (vifi = 0; vifi < cache->_c.mfc_un.res.maxvif; vifi++) { ++ if (!((cache->_c.mfc_un.res.ttls[vifi] > 0) && ++ (cache->_c.mfc_un.res.ttls[vifi] < 255))) { ++ continue; ++ } ++ if (dest_if_count == MAXVIFS) { ++ read_unlock(&mrt_lock); ++ return; ++ } ++ ++ if (!VIF_EXISTS(mrt, vifi)) { ++ read_unlock(&mrt_lock); ++ return; ++ } ++ dest_dev[dest_if_count] = mrt->vif_table[vifi].dev->ifindex; ++ dest_if_count++; ++ } ++ read_unlock(&mrt_lock); ++ ++ rcu_read_lock(); ++ offload_update_cb_f = rcu_dereference(ipmr_mfc_event_offload_callback); ++ ++ if (!offload_update_cb_f) { ++ rcu_read_unlock(); ++ return; ++ } ++ ++ offload_update_cb_f(group, origin, dest_if_count, dest_dev, ++ IPMR_MFC_EVENT_UPDATE); ++ rcu_read_unlock(); ++} ++ ++/* ipmr_sync_entry_delete() ++ * Call the registered offload callback to inform of a multicast route entry ++ * delete event ++ */ ++static void ipmr_sync_entry_delete(u32 origin, u32 group) ++{ ++ ipmr_mfc_event_offload_callback_t offload_update_cb_f; ++ ++ rcu_read_lock(); ++ offload_update_cb_f = rcu_dereference(ipmr_mfc_event_offload_callback); ++ ++ if (!offload_update_cb_f) { ++ rcu_read_unlock(); ++ return; ++ } ++ ++ offload_update_cb_f(group, origin, 0, NULL, IPMR_MFC_EVENT_DELETE); ++ rcu_read_unlock(); ++} ++ ++/* ipmr_register_mfc_event_offload_callback() ++ * Register the IPv4 Multicast update offload callback with IPMR ++ */ ++bool ipmr_register_mfc_event_offload_callback( ++ ipmr_mfc_event_offload_callback_t mfc_offload_cb) ++{ ++ ipmr_mfc_event_offload_callback_t offload_update_cb_f; ++ ++ rcu_read_lock(); ++ offload_update_cb_f = rcu_dereference(ipmr_mfc_event_offload_callback); ++ ++ if (offload_update_cb_f) { ++ rcu_read_unlock(); ++ return false; ++ } ++ rcu_read_unlock(); ++ ++ spin_lock(&lock); ++ rcu_assign_pointer(ipmr_mfc_event_offload_callback, mfc_offload_cb); ++ spin_unlock(&lock); ++ synchronize_rcu(); ++ return true; ++} ++EXPORT_SYMBOL(ipmr_register_mfc_event_offload_callback); ++ ++/* ipmr_unregister_mfc_event_offload_callback() ++ * De-register the IPv4 Multicast update offload callback with IPMR ++ */ ++void ipmr_unregister_mfc_event_offload_callback(void) ++{ ++ spin_lock(&lock); ++ rcu_assign_pointer(ipmr_mfc_event_offload_callback, NULL); ++ spin_unlock(&lock); ++ synchronize_rcu(); ++} ++EXPORT_SYMBOL(ipmr_unregister_mfc_event_offload_callback); ++ ++/* ipmr_find_mfc_entry() ++ * Returns destination interface list for a particular multicast flow, and ++ * the number of interfaces in the list ++ */ ++int ipmr_find_mfc_entry(struct net *net, __be32 origin, __be32 group, ++ u32 max_dest_cnt, u32 dest_dev[]) ++{ ++ int vifi, dest_if_count = 0; ++ struct mr_table *mrt; ++ struct mfc_cache *cache; ++ ++ mrt = ipmr_get_table(net, RT_TABLE_DEFAULT); ++ if (!mrt) ++ return -ENOENT; ++ ++ rcu_read_lock(); ++ cache = ipmr_cache_find(mrt, origin, group); ++ if (!cache) { ++ rcu_read_unlock(); ++ return -ENOENT; ++ } ++ ++ read_lock(&mrt_lock); ++ for (vifi = 0; vifi < cache->_c.mfc_un.res.maxvif; vifi++) { ++ if (!((cache->_c.mfc_un.res.ttls[vifi] > 0) && ++ (cache->_c.mfc_un.res.ttls[vifi] < 255))) { ++ continue; ++ } ++ ++ /* We have another valid destination interface entry. Check if ++ * the number of the destination interfaces for the route is ++ * exceeding the size of the array given to us ++ */ ++ if (dest_if_count == max_dest_cnt) { ++ read_unlock(&mrt_lock); ++ rcu_read_unlock(); ++ return -EINVAL; ++ } ++ ++ if (!VIF_EXISTS(mrt, vifi)) { ++ read_unlock(&mrt_lock); ++ rcu_read_unlock(); ++ return -EINVAL; ++ } ++ ++ dest_dev[dest_if_count] = mrt->vif_table[vifi].dev->ifindex; ++ dest_if_count++; ++ } ++ read_unlock(&mrt_lock); ++ rcu_read_unlock(); ++ ++ return dest_if_count; ++} ++EXPORT_SYMBOL(ipmr_find_mfc_entry); ++ ++/* ipmr_mfc_stats_update() ++ * Update the MFC/VIF statistics for offloaded flows ++ */ ++int ipmr_mfc_stats_update(struct net *net, __be32 origin, __be32 group, ++ u64 pkts_in, u64 bytes_in, ++ u64 pkts_out, u64 bytes_out) ++{ ++ int vif, vifi; ++ struct mr_table *mrt; ++ struct mfc_cache *cache; ++ ++ mrt = ipmr_get_table(net, RT_TABLE_DEFAULT); ++ if (!mrt) ++ return -ENOENT; ++ ++ rcu_read_lock(); ++ cache = ipmr_cache_find(mrt, origin, group); ++ if (!cache) { ++ rcu_read_unlock(); ++ return -ENOENT; ++ } ++ ++ vif = cache->_c.mfc_parent; ++ ++ read_lock(&mrt_lock); ++ if (!VIF_EXISTS(mrt, vif)) { ++ read_unlock(&mrt_lock); ++ rcu_read_unlock(); ++ return -EINVAL; ++ } ++ ++ mrt->vif_table[vif].pkt_in += pkts_in; ++ mrt->vif_table[vif].bytes_in += bytes_in; ++ cache->_c.mfc_un.res.pkt += pkts_out; ++ cache->_c.mfc_un.res.bytes += bytes_out; ++ ++ for (vifi = cache->_c.mfc_un.res.minvif; ++ vifi < cache->_c.mfc_un.res.maxvif; vifi++) { ++ if ((cache->_c.mfc_un.res.ttls[vifi] > 0) && ++ (cache->_c.mfc_un.res.ttls[vifi] < 255)) { ++ if (!VIF_EXISTS(mrt, vifi)) { ++ read_unlock(&mrt_lock); ++ rcu_read_unlock(); ++ return -EINVAL; ++ } ++ mrt->vif_table[vifi].pkt_out += pkts_out; ++ mrt->vif_table[vifi].bytes_out += bytes_out; ++ } ++ } ++ read_unlock(&mrt_lock); ++ rcu_read_unlock(); ++ ++ return 0; ++} ++EXPORT_SYMBOL(ipmr_mfc_stats_update); ++/* QCA ECM qca-mcs support - End */ ++ + static const struct fib_rules_ops __net_initconst ipmr_rules_ops_template = { + .family = RTNL_FAMILY_IPMR, + .rule_size = sizeof(struct ipmr_rule), +@@ -1185,6 +1416,11 @@ static int ipmr_mfc_delete(struct mr_tab + mroute_netlink_event(mrt, c, RTM_DELROUTE); + mr_cache_put(&c->_c); + ++ /* QCA ECM qca-mcs support - Start */ ++ /* Inform offload modules of the delete event */ ++ ipmr_sync_entry_delete(c->mfc_origin, c->mfc_mcastgrp); ++ /* QCA ECM qca-mcs support - End */ ++ + return 0; + } + +@@ -1214,6 +1450,12 @@ static int ipmr_mfc_add(struct net *net, + call_ipmr_mfc_entry_notifiers(net, FIB_EVENT_ENTRY_REPLACE, c, + mrt->id); + mroute_netlink_event(mrt, c, RTM_NEWROUTE); ++ ++ /* QCA ECM qca-mcs support - Start */ ++ /* Inform offload modules of the update event */ ++ ipmr_sync_entry_update(mrt, c); ++ /* QCA ECM qca-mcs support - End */ ++ + return 0; + } + +@@ -1274,6 +1516,7 @@ static void mroute_clean_tables(struct m + struct net *net = read_pnet(&mrt->net); + struct mr_mfc *c, *tmp; + struct mfc_cache *cache; ++ u32 origin, group; /* QCA ECM qca-mcs support */ + LIST_HEAD(list); + int i; + +@@ -1298,10 +1541,19 @@ static void mroute_clean_tables(struct m + rhltable_remove(&mrt->mfc_hash, &c->mnode, ipmr_rht_params); + list_del_rcu(&c->list); + cache = (struct mfc_cache *)c; ++ /* QCA ECM qca-mcs support - Start */ ++ origin = cache->mfc_origin; ++ group = cache->mfc_mcastgrp; ++ /* QCA ECM qca-mcs support - End */ + call_ipmr_mfc_entry_notifiers(net, FIB_EVENT_ENTRY_DEL, cache, + mrt->id); + mroute_netlink_event(mrt, cache, RTM_DELROUTE); + mr_cache_put(c); ++ ++ /* QCA ECM qca-mcs support - Start */ ++ /* Inform offload modules of the delete event */ ++ ipmr_sync_entry_delete(origin, group); ++ /* QCA ECM qca-mcs support - End */ + } + } + +--- a/net/ipv6/ip6mr.c ++++ b/net/ipv6/ip6mr.c +@@ -95,6 +95,17 @@ static int ip6mr_rtm_dumproute(struct sk + static void mroute_clean_tables(struct mr_table *mrt, int flags); + static void ipmr_expire_process(struct timer_list *t); + ++/* QCA qca-mcs support - Start */ ++/* Spinlock for offload */ ++static DEFINE_SPINLOCK(lock); ++ ++static struct mfc6_cache *ip6mr_cache_find(struct mr_table *mrt, ++ const struct in6_addr *origin, ++ const struct in6_addr *mcastgrp); ++static ip6mr_mfc_event_offload_callback_t __rcu ++ ip6mr_mfc_event_offload_callback; ++/* QCA qca-mcs support - End */ ++ + #ifdef CONFIG_IPV6_MROUTE_MULTIPLE_TABLES + #define ip6mr_for_each_table(mrt, net) \ + list_for_each_entry_rcu(mrt, &net->ipv6.mr6_tables, list, \ +@@ -380,6 +391,227 @@ static struct mr_table_ops ip6mr_mr_tabl + .cmparg_any = &ip6mr_mr_table_ops_cmparg_any, + }; + ++/* QCA qca-mcs support - Start */ ++/* ip6mr_sync_entry_update() ++ * Call the registered offload callback to report an update to a multicast ++ * route entry. The callback receives the list of destination interfaces and ++ * the interface count ++ */ ++static void ip6mr_sync_entry_update(struct mr_table *mrt, ++ struct mfc6_cache *cache) ++{ ++ int vifi, dest_if_count = 0; ++ u32 dest_dev[MAXMIFS]; ++ struct in6_addr mc_origin, mc_group; ++ ip6mr_mfc_event_offload_callback_t offload_update_cb_f; ++ ++ memset(dest_dev, 0, sizeof(dest_dev)); ++ ++ read_lock(&mrt_lock); ++ ++ for (vifi = 0; vifi < cache->_c.mfc_un.res.maxvif; vifi++) { ++ if (!((cache->_c.mfc_un.res.ttls[vifi] > 0) && ++ (cache->_c.mfc_un.res.ttls[vifi] < 255))) { ++ continue; ++ } ++ ++ if (dest_if_count == MAXMIFS) { ++ read_unlock(&mrt_lock); ++ return; ++ } ++ ++ if (!VIF_EXISTS(mrt, vifi)) { ++ read_unlock(&mrt_lock); ++ return; ++ } ++ ++ dest_dev[dest_if_count] = mrt->vif_table[vifi].dev->ifindex; ++ dest_if_count++; ++ } ++ ++ memcpy(&mc_origin, &cache->mf6c_origin, sizeof(struct in6_addr)); ++ memcpy(&mc_group, &cache->mf6c_mcastgrp, sizeof(struct in6_addr)); ++ read_unlock(&mrt_lock); ++ ++ rcu_read_lock(); ++ offload_update_cb_f = rcu_dereference(ip6mr_mfc_event_offload_callback); ++ ++ if (!offload_update_cb_f) { ++ rcu_read_unlock(); ++ return; ++ } ++ ++ offload_update_cb_f(&mc_group, &mc_origin, dest_if_count, dest_dev, ++ IP6MR_MFC_EVENT_UPDATE); ++ rcu_read_unlock(); ++} ++ ++/* ip6mr_sync_entry_delete() ++ * Call the registered offload callback to inform of a multicast route entry ++ * delete event ++ */ ++static void ip6mr_sync_entry_delete(struct in6_addr *mc_origin, ++ struct in6_addr *mc_group) ++{ ++ ip6mr_mfc_event_offload_callback_t offload_update_cb_f; ++ ++ rcu_read_lock(); ++ offload_update_cb_f = rcu_dereference(ip6mr_mfc_event_offload_callback); ++ ++ if (!offload_update_cb_f) { ++ rcu_read_unlock(); ++ return; ++ } ++ ++ offload_update_cb_f(mc_group, mc_origin, 0, NULL, ++ IP6MR_MFC_EVENT_DELETE); ++ rcu_read_unlock(); ++} ++ ++/* ip6mr_register_mfc_event_offload_callback() ++ * Register the IPv6 multicast update callback for offload modules ++ */ ++bool ip6mr_register_mfc_event_offload_callback( ++ ip6mr_mfc_event_offload_callback_t mfc_offload_cb) ++{ ++ ip6mr_mfc_event_offload_callback_t offload_update_cb_f; ++ ++ rcu_read_lock(); ++ offload_update_cb_f = rcu_dereference(ip6mr_mfc_event_offload_callback); ++ ++ if (offload_update_cb_f) { ++ rcu_read_unlock(); ++ return false; ++ } ++ rcu_read_unlock(); ++ ++ spin_lock(&lock); ++ rcu_assign_pointer(ip6mr_mfc_event_offload_callback, mfc_offload_cb); ++ spin_unlock(&lock); ++ synchronize_rcu(); ++ return true; ++} ++EXPORT_SYMBOL(ip6mr_register_mfc_event_offload_callback); ++ ++/* ip6mr_unregister_mfc_event_offload_callback() ++ * De-register the IPv6 multicast update callback for offload modules ++ */ ++void ip6mr_unregister_mfc_event_offload_callback(void) ++{ ++ spin_lock(&lock); ++ rcu_assign_pointer(ip6mr_mfc_event_offload_callback, NULL); ++ spin_unlock(&lock); ++ synchronize_rcu(); ++} ++EXPORT_SYMBOL(ip6mr_unregister_mfc_event_offload_callback); ++ ++/* ip6mr_find_mfc_entry() ++ * Return the destination interface list for a particular multicast flow, and ++ * the number of interfaces in the list ++ */ ++int ip6mr_find_mfc_entry(struct net *net, struct in6_addr *origin, ++ struct in6_addr *group, u32 max_dest_cnt, ++ u32 dest_dev[]) ++{ ++ int vifi, dest_if_count = 0; ++ struct mr_table *mrt; ++ struct mfc6_cache *cache; ++ ++ mrt = ip6mr_get_table(net, RT6_TABLE_DFLT); ++ if (!mrt) ++ return -ENOENT; ++ ++ read_lock(&mrt_lock); ++ cache = ip6mr_cache_find(mrt, origin, group); ++ if (!cache) { ++ read_unlock(&mrt_lock); ++ return -ENOENT; ++ } ++ ++ for (vifi = 0; vifi < cache->_c.mfc_un.res.maxvif; vifi++) { ++ if (!((cache->_c.mfc_un.res.ttls[vifi] > 0) && ++ (cache->_c.mfc_un.res.ttls[vifi] < 255))) { ++ continue; ++ } ++ ++ /* We have another valid destination interface entry. Check if ++ * the number of the destination interfaces for the route is ++ * exceeding the size of the array given to us ++ */ ++ if (dest_if_count == max_dest_cnt) { ++ read_unlock(&mrt_lock); ++ return -EINVAL; ++ } ++ ++ if (!VIF_EXISTS(mrt, vifi)) { ++ read_unlock(&mrt_lock); ++ return -EINVAL; ++ } ++ ++ dest_dev[dest_if_count] = mrt->vif_table[vifi].dev->ifindex; ++ dest_if_count++; ++ } ++ read_unlock(&mrt_lock); ++ ++ return dest_if_count; ++} ++EXPORT_SYMBOL(ip6mr_find_mfc_entry); ++ ++/* ip6mr_mfc_stats_update() ++ * Update the MFC/VIF statistics for offloaded flows ++ */ ++int ip6mr_mfc_stats_update(struct net *net, struct in6_addr *origin, ++ struct in6_addr *group, u64 pkts_in, ++ u64 bytes_in, uint64_t pkts_out, ++ u64 bytes_out) ++{ ++ int vif, vifi; ++ struct mr_table *mrt; ++ struct mfc6_cache *cache; ++ ++ mrt = ip6mr_get_table(net, RT6_TABLE_DFLT); ++ ++ if (!mrt) ++ return -ENOENT; ++ ++ read_lock(&mrt_lock); ++ cache = ip6mr_cache_find(mrt, origin, group); ++ if (!cache) { ++ read_unlock(&mrt_lock); ++ return -ENOENT; ++ } ++ ++ vif = cache->_c.mfc_parent; ++ ++ if (!VIF_EXISTS(mrt, vif)) { ++ read_unlock(&mrt_lock); ++ return -EINVAL; ++ } ++ ++ mrt->vif_table[vif].pkt_in += pkts_in; ++ mrt->vif_table[vif].bytes_in += bytes_in; ++ cache->_c.mfc_un.res.pkt += pkts_out; ++ cache->_c.mfc_un.res.bytes += bytes_out; ++ ++ for (vifi = cache->_c.mfc_un.res.minvif; ++ vifi < cache->_c.mfc_un.res.maxvif; vifi++) { ++ if ((cache->_c.mfc_un.res.ttls[vifi] > 0) && ++ (cache->_c.mfc_un.res.ttls[vifi] < 255)) { ++ if (!VIF_EXISTS(mrt, vifi)) { ++ read_unlock(&mrt_lock); ++ return -EINVAL; ++ } ++ mrt->vif_table[vifi].pkt_out += pkts_out; ++ mrt->vif_table[vifi].bytes_out += bytes_out; ++ } ++ } ++ ++ read_unlock(&mrt_lock); ++ return 0; ++} ++EXPORT_SYMBOL(ip6mr_mfc_stats_update); ++/* QCA qca-mcs support - End */ ++ + static struct mr_table *ip6mr_new_table(struct net *net, u32 id) + { + struct mr_table *mrt; +@@ -1215,6 +1447,7 @@ static int ip6mr_mfc_delete(struct mr_ta + int parent) + { + struct mfc6_cache *c; ++ struct in6_addr mc_origin, mc_group; /* QCA qca-mcs support */ + + /* The entries are added/deleted only under RTNL */ + rcu_read_lock(); +@@ -1223,6 +1456,12 @@ static int ip6mr_mfc_delete(struct mr_ta + rcu_read_unlock(); + if (!c) + return -ENOENT; ++ ++ /* QCA qca-mcs support - Start */ ++ memcpy(&mc_origin, &c->mf6c_origin, sizeof(struct in6_addr)); ++ memcpy(&mc_group, &c->mf6c_mcastgrp, sizeof(struct in6_addr)); ++ /* QCA qca-mcs support - End */ ++ + rhltable_remove(&mrt->mfc_hash, &c->_c.mnode, ip6mr_rht_params); + list_del_rcu(&c->_c.list); + +@@ -1230,6 +1469,12 @@ static int ip6mr_mfc_delete(struct mr_ta + FIB_EVENT_ENTRY_DEL, c, mrt->id); + mr6_netlink_event(mrt, c, RTM_DELROUTE); + mr_cache_put(&c->_c); ++ ++ /* QCA qca-mcs support - Start */ ++ /* Inform offload modules of the delete event */ ++ ip6mr_sync_entry_delete(&mc_origin, &mc_group); ++ /* QCA qca-mcs support - End */ ++ + return 0; + } + +@@ -1439,6 +1684,12 @@ static int ip6mr_mfc_add(struct net *net + call_ip6mr_mfc_entry_notifiers(net, FIB_EVENT_ENTRY_REPLACE, + c, mrt->id); + mr6_netlink_event(mrt, c, RTM_NEWROUTE); ++ ++ /* QCA qca-mcs support - Start */ ++ /* Inform offload modules of the update event */ ++ ip6mr_sync_entry_update(mrt, c); ++ /* QCA qca-mcs support - End */ ++ + return 0; + } + +@@ -1501,6 +1752,10 @@ static int ip6mr_mfc_add(struct net *net + + static void mroute_clean_tables(struct mr_table *mrt, int flags) + { ++ /* QCA qca-mcs support - Start */ ++ struct mfc6_cache *cache; ++ struct in6_addr mc_origin, mc_group; ++ /* QCA qca-mcs support - End */ + struct mr_mfc *c, *tmp; + LIST_HEAD(list); + int i; +@@ -1523,13 +1778,23 @@ static void mroute_clean_tables(struct m + if (((c->mfc_flags & MFC_STATIC) && !(flags & MRT6_FLUSH_MFC_STATIC)) || + (!(c->mfc_flags & MFC_STATIC) && !(flags & MRT6_FLUSH_MFC))) + continue; ++ /* QCA qca-mcs support - Start */ ++ cache = (struct mfc6_cache *)c; ++ memcpy(&mc_origin, &cache->mf6c_origin, sizeof(struct in6_addr)); ++ memcpy(&mc_group, &cache->mf6c_mcastgrp, sizeof(struct in6_addr)); ++ /* QCA qca-mcs support - End */ + rhltable_remove(&mrt->mfc_hash, &c->mnode, ip6mr_rht_params); + list_del_rcu(&c->list); + call_ip6mr_mfc_entry_notifiers(read_pnet(&mrt->net), + FIB_EVENT_ENTRY_DEL, +- (struct mfc6_cache *)c, mrt->id); +- mr6_netlink_event(mrt, (struct mfc6_cache *)c, RTM_DELROUTE); ++ cache, mrt->id); ++ mr6_netlink_event(mrt, cache, RTM_DELROUTE); + mr_cache_put(c); ++ ++ /* QCA qca-mcs support - Start */ ++ /* Inform offload modules of the delete event */ ++ ip6mr_sync_entry_delete(&mc_origin, &mc_group); ++ /* QCA qca-mcs support - End */ + } + } + diff --git a/target/linux/ipq806x/patches-5.15/999-500-qca-nss-cfi-support.patch b/target/linux/ipq806x/patches-5.15/999-500-qca-nss-cfi-support.patch new file mode 100644 index 0000000000..d265624a29 --- /dev/null +++ b/target/linux/ipq806x/patches-5.15/999-500-qca-nss-cfi-support.patch @@ -0,0 +1,111 @@ +--- a/crypto/authenc.c ++++ b/crypto/authenc.c +@@ -417,6 +417,8 @@ static int crypto_authenc_create(struct + enc->base.cra_driver_name) >= CRYPTO_MAX_ALG_NAME) + goto err_free_inst; + ++ inst->alg.base.cra_flags |= (auth_base->cra_flags | ++ enc->base.cra_flags) & CRYPTO_ALG_NOSUPP_SG; + inst->alg.base.cra_priority = enc->base.cra_priority * 10 + + auth_base->cra_priority; + inst->alg.base.cra_blocksize = enc->base.cra_blocksize; +--- a/include/linux/crypto.h ++++ b/include/linux/crypto.h +@@ -101,6 +101,11 @@ + #define CRYPTO_NOLOAD 0x00008000 + + /* ++ * Set this flag if algorithm does not support SG list transforms ++ */ ++#define CRYPTO_ALG_NOSUPP_SG 0x0000c000 ++ ++/* + * The algorithm may allocate memory during request processing, i.e. during + * encryption, decryption, or hashing. Users can request an algorithm with this + * flag unset if they can't handle memory allocation failures. +--- a/net/ipv4/esp4.c ++++ b/net/ipv4/esp4.c +@@ -659,6 +659,7 @@ static int esp_output(struct xfrm_state + struct ip_esp_hdr *esph; + struct crypto_aead *aead; + struct esp_info esp; ++ bool nosupp_sg; + + esp.inplace = true; + +@@ -670,6 +671,11 @@ static int esp_output(struct xfrm_state + aead = x->data; + alen = crypto_aead_authsize(aead); + ++ nosupp_sg = crypto_tfm_alg_type(&aead->base) & CRYPTO_ALG_NOSUPP_SG; ++ if (nosupp_sg && skb_linearize(skb)) { ++ return -ENOMEM; ++ } ++ + esp.tfclen = 0; + if (x->tfcpad) { + struct xfrm_dst *dst = (struct xfrm_dst *)skb_dst(skb); +@@ -895,6 +901,7 @@ static int esp_input(struct xfrm_state * + u8 *iv; + struct scatterlist *sg; + int err = -EINVAL; ++ bool nosupp_sg; + + if (!pskb_may_pull(skb, sizeof(struct ip_esp_hdr) + ivlen)) + goto out; +@@ -902,6 +909,12 @@ static int esp_input(struct xfrm_state * + if (elen <= 0) + goto out; + ++ nosupp_sg = crypto_tfm_alg_type(&aead->base) & CRYPTO_ALG_NOSUPP_SG; ++ if (nosupp_sg && skb_linearize(skb)) { ++ err = -ENOMEM; ++ goto out; ++ } ++ + assoclen = sizeof(struct ip_esp_hdr); + seqhilen = 0; + +--- a/net/ipv6/esp6.c ++++ b/net/ipv6/esp6.c +@@ -696,6 +696,7 @@ static int esp6_output(struct xfrm_state + struct ip_esp_hdr *esph; + struct crypto_aead *aead; + struct esp_info esp; ++ bool nosupp_sg; + + esp.inplace = true; + +@@ -707,6 +708,11 @@ static int esp6_output(struct xfrm_state + aead = x->data; + alen = crypto_aead_authsize(aead); + ++ nosupp_sg = crypto_tfm_alg_type(&aead->base) & CRYPTO_ALG_NOSUPP_SG; ++ if (nosupp_sg && skb_linearize(skb)) { ++ return -ENOMEM; ++ } ++ + esp.tfclen = 0; + if (x->tfcpad) { + struct xfrm_dst *dst = (struct xfrm_dst *)skb_dst(skb); +@@ -938,6 +944,7 @@ static int esp6_input(struct xfrm_state + __be32 *seqhi; + u8 *iv; + struct scatterlist *sg; ++ bool nosupp_sg; + + if (!pskb_may_pull(skb, sizeof(struct ip_esp_hdr) + ivlen)) { + ret = -EINVAL; +@@ -949,6 +956,12 @@ static int esp6_input(struct xfrm_state + goto out; + } + ++ nosupp_sg = crypto_tfm_alg_type(&aead->base) & CRYPTO_ALG_NOSUPP_SG; ++ if (nosupp_sg && skb_linearize(skb)) { ++ ret = -ENOMEM; ++ goto out; ++ } ++ + assoclen = sizeof(struct ip_esp_hdr); + seqhilen = 0; + diff --git a/target/linux/ipq806x/patches-5.15/999-600-disable-unused-nss-feat.patch b/target/linux/ipq806x/patches-5.15/999-600-disable-unused-nss-feat.patch new file mode 100644 index 0000000000..afa41db439 --- /dev/null +++ b/target/linux/ipq806x/patches-5.15/999-600-disable-unused-nss-feat.patch @@ -0,0 +1,24 @@ +--- a/arch/arm/boot/dts/qcom-ipq8064.dtsi ++++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi +@@ -1513,7 +1513,6 @@ + qcom,load-addr = <0x40000000>; + qcom,turbo-frequency; + +- qcom,bridge-enabled; + qcom,gre-enabled; + qcom,gre-redir-enabled; + qcom,gre_tunnel_enabled; +@@ -1532,12 +1531,10 @@ + qcom,vlan-enabled; + qcom,wlan-dataplane-offload-enabled; + qcom,wlanredirect-enabled; +- qcom,pxvlan-enabled; + qcom,vxlan-enabled; + qcom,match-enabled; + qcom,mirror-enabled; +- qcom,rmnet-enabled; +- qcom,clmap-enabled; ++ qcom,tstamp-enabled; + }; + + nss1: nss@40800000 { diff --git a/target/linux/ipq806x/patches-5.15/999-800-qca-nss-ecm-12.1-drop-unused.patch b/target/linux/ipq806x/patches-5.15/999-800-qca-nss-ecm-12.1-drop-unused.patch new file mode 100644 index 0000000000..ada346591f --- /dev/null +++ b/target/linux/ipq806x/patches-5.15/999-800-qca-nss-ecm-12.1-drop-unused.patch @@ -0,0 +1,160 @@ +--- a/include/linux/if_bridge.h ++++ b/include/linux/if_bridge.h +@@ -198,7 +198,6 @@ extern struct net_device *br_port_dev_ge + unsigned char *addr, + struct sk_buff *skb, + unsigned int cookie); +-extern void br_refresh_fdb_entry(struct net_device *dev, const char *addr); + extern void br_fdb_entry_refresh(struct net_device *dev, const char *addr, __u16 vid); + extern struct net_bridge_fdb_entry *br_fdb_has_entry(struct net_device *dev, + const char *addr, +--- a/net/bridge/br_fdb.c ++++ b/net/bridge/br_fdb.c +@@ -1465,26 +1465,6 @@ void br_fdb_clear_offload(const struct n + EXPORT_SYMBOL_GPL(br_fdb_clear_offload); + + /* QCA NSS ECM support - Start */ +-/* Refresh FDB entries for bridge packets being forwarded by offload engines */ +-void br_refresh_fdb_entry(struct net_device *dev, const char *addr) +-{ +- struct net_bridge_port *p = br_port_get_rcu(dev); +- +- if (!p || p->state == BR_STATE_DISABLED) +- return; +- +- if (!is_valid_ether_addr(addr)) { +- pr_info("bridge: Attempt to refresh with invalid ether address %pM\n", +- addr); +- return; +- } +- +- rcu_read_lock(); +- br_fdb_update(p->br, p, addr, 0, true); +- rcu_read_unlock(); +-} +-EXPORT_SYMBOL_GPL(br_refresh_fdb_entry); +- + /* Update timestamp of FDB entries for bridge packets being forwarded by offload engines */ + void br_fdb_entry_refresh(struct net_device *dev, const char *addr, __u16 vid) + { +--- a/drivers/net/ppp/ppp_generic.c ++++ b/drivers/net/ppp/ppp_generic.c +@@ -3772,34 +3772,6 @@ int ppp_channel_get_proto_version(struct + } + EXPORT_SYMBOL(ppp_channel_get_proto_version); + +-/* ppp_channel_hold() +- * Call this to hold a channel. +- * +- * Returns true on success or false if the hold could not happen. +- * +- * NOTE: chan must be protected against destruction during this call - +- * either by correct locking etc. or because you already have an implicit +- * or explicit hold to the channel already and this is an additional hold. +- */ +-bool ppp_channel_hold(struct ppp_channel *chan) +-{ +- if (!chan->ops->hold) +- return false; +- +- chan->ops->hold(chan); +- return true; +-} +-EXPORT_SYMBOL(ppp_channel_hold); +- +-/* ppp_channel_release() +- * Call this to release a hold you have upon a channel +- */ +-void ppp_channel_release(struct ppp_channel *chan) +-{ +- chan->ops->release(chan); +-} +-EXPORT_SYMBOL(ppp_channel_release); +- + /* Check if ppp xmit lock is on hold */ + bool ppp_is_xmit_locked(struct net_device *dev) + { +--- a/include/linux/ppp_channel.h ++++ b/include/linux/ppp_channel.h +@@ -99,12 +99,6 @@ extern int ppp_channel_get_protocol(stru + /* Call this get protocol version */ + extern int ppp_channel_get_proto_version(struct ppp_channel *); + +-/* Call this to hold a channel */ +-extern bool ppp_channel_hold(struct ppp_channel *); +- +-/* Call this to release a hold you have upon a channel */ +-extern void ppp_channel_release(struct ppp_channel *); +- + /* Release hold on PPP channels */ + extern void ppp_release_channels(struct ppp_channel *channels[], + unsigned int chan_sz); +--- a/drivers/net/ppp/pptp.c ++++ b/drivers/net/ppp/pptp.c +@@ -92,32 +92,6 @@ static int lookup_chan_dst(u16 call_id, + return i < MAX_CALLID; + } + +-/* Search a pptp session based on local call id, local and remote ip address */ +-static int lookup_session_src(struct pptp_opt *opt, u16 call_id, __be32 daddr, __be32 saddr) +-{ +- struct pppox_sock *sock; +- int i = 1; +- +- rcu_read_lock(); +- for_each_set_bit_from(i, callid_bitmap, MAX_CALLID) { +- sock = rcu_dereference(callid_sock[i]); +- if (!sock) +- continue; +- +- if (sock->proto.pptp.src_addr.call_id == call_id && +- sock->proto.pptp.dst_addr.sin_addr.s_addr == daddr && +- sock->proto.pptp.src_addr.sin_addr.s_addr == saddr) { +- sock_hold(sk_pppox(sock)); +- memcpy(opt, &sock->proto.pptp, sizeof(struct pptp_opt)); +- sock_put(sk_pppox(sock)); +- rcu_read_unlock(); +- return 0; +- } +- } +- rcu_read_unlock(); +- return -EINVAL; +-} +- + /* Search a pptp session based on peer call id and peer ip address */ + static int lookup_session_dst(struct pptp_opt *opt, u16 call_id, __be32 d_addr) + { +@@ -748,20 +722,6 @@ int pptp_session_find(struct pptp_opt *o + } + EXPORT_SYMBOL(pptp_session_find); + +-/* pptp_session_find_by_src_callid() +- * Search and return a PPTP session info based on src callid and IP +- * address. The function accepts the parameters in network byte order. +- */ +-int pptp_session_find_by_src_callid(struct pptp_opt *opt, __be16 src_call_id, +- __be32 daddr, __be32 saddr) +-{ +- if (!opt) +- return -EINVAL; +- +- return lookup_session_src(opt, ntohs(src_call_id), daddr, saddr); +-} +-EXPORT_SYMBOL(pptp_session_find_by_src_callid); +- + /* Function to change the offload mode true/false for a PPTP session */ + static int pptp_set_offload_mode(bool accel_mode, + __be16 peer_call_id, __be32 peer_ip_addr) +--- a/include/linux/if_pppox.h ++++ b/include/linux/if_pppox.h +@@ -111,10 +111,6 @@ typedef int (*pptp_gre_seq_offload_callb + extern int pppoe_channel_addressing_get(struct ppp_channel *chan, + struct pppoe_opt *addressing); + +-/* Lookup PPTP session info and return PPTP session using sip, dip and local call id */ +-extern int pptp_session_find_by_src_callid(struct pptp_opt *opt, __be16 src_call_id, +- __be32 daddr, __be32 saddr); +- + /* Lookup PPTP session info and return PPTP session using dip and peer call id */ + extern int pptp_session_find(struct pptp_opt *opt, __be16 peer_call_id, + __be32 peer_ip_addr);