609 lines
18 KiB
Diff
609 lines
18 KiB
Diff
From 16de3e75ec92f88a454725c2e33e22b501c1a873 Mon Sep 17 00:00:00 2001
|
|
From: Murat Sezgin <quic_msezgin@quicinc.com>
|
|
Date: Wed, 10 May 2023 13:16:09 -0700
|
|
Subject: [PATCH 183/500] ppp: PPPoE acceleration support.
|
|
|
|
pppoe: Add return value to pppoe addressing get function
|
|
|
|
If the addressing doesn't have a netdevice, this should be
|
|
handled as a failure, so that the caller considers that
|
|
the get function failed.
|
|
|
|
Change-Id: Ia9a6b0e0f036a3434519d9f2194763486ca04583
|
|
Signed-off-by: Murat Sezgin <msezgin@codeaurora.org>
|
|
|
|
Added some new APIs to the PPP/PPPoE kernel modules
|
|
for using from the hardware acceleration connection managers.
|
|
|
|
Change-Id: I2c16c6d6ccba8ffa14aec077c8dad1681535ae0b
|
|
Signed-off-by: Murat Sezgin <msezgin@codeaurora.org>
|
|
|
|
net: ppp: rx/tx error and dropped pkt stats support
|
|
|
|
ppp_update_stats functions accepts rx/tx errors and dropped
|
|
pkt stats args.
|
|
|
|
Change-Id: Iba2f6ea2114d8a4678254332fec0ef7bc35bed2c
|
|
Signed-off-by: ratheesh kannoth <rkannoth@codeaurora.org>
|
|
Signed-off-by: Murat Sezgin <msezgin@codeaurora.org>
|
|
|
|
ppp: Update the last_recv and last_xmit times.
|
|
|
|
These need to be updated for accelerated connections, so that
|
|
on demand mode will recognize the active traffic.
|
|
|
|
Change-Id: I3c0ee4e8f4c3bc4c7ce221e6109bfd82046d11b4
|
|
Signed-off-by: Murat Sezgin <msezgin@codeaurora.org>
|
|
|
|
ppp: Add channel connect/disconnect notifier.
|
|
|
|
When a channel is connected or disconnected to a PPP
|
|
unit, a notification will be sent to the kernel subsystems
|
|
which are registered to this notifier. Notifier sends
|
|
the event type (connect or disconnect) along with the
|
|
PPP netdevice pointer.
|
|
|
|
Change-Id: I0d592084744c86e1c114ac66da68b214ddff5b5a
|
|
Signed-off-by: Murat Sezgin <msezgin@codeaurora.org>
|
|
Signed-off-by: Murat Sezgin <quic_msezgin@quicinc.com>
|
|
---
|
|
drivers/net/ppp/ppp_generic.c | 220 ++++++++++++++++++++++++++++++++++
|
|
drivers/net/ppp/pppoe.c | 83 ++++++++++++-
|
|
include/linux/if_pppox.h | 16 ++-
|
|
include/linux/ppp_channel.h | 52 ++++++++
|
|
net/l2tp/l2tp_core.c | 24 ++++
|
|
net/l2tp/l2tp_core.h | 2 +
|
|
6 files changed, 391 insertions(+), 6 deletions(-)
|
|
|
|
--- a/drivers/net/ppp/ppp_generic.c
|
|
+++ b/drivers/net/ppp/ppp_generic.c
|
|
@@ -255,6 +255,24 @@ struct ppp_net {
|
|
#define seq_before(a, b) ((s32)((a) - (b)) < 0)
|
|
#define seq_after(a, b) ((s32)((a) - (b)) > 0)
|
|
|
|
+/*
|
|
+ * Registration/Unregistration methods
|
|
+ * for PPP channel connect and disconnect event notifications.
|
|
+ */
|
|
+RAW_NOTIFIER_HEAD(ppp_channel_connection_notifier_list);
|
|
+
|
|
+void ppp_channel_connection_register_notify(struct notifier_block *nb)
|
|
+{
|
|
+ raw_notifier_chain_register(&ppp_channel_connection_notifier_list, nb);
|
|
+}
|
|
+EXPORT_SYMBOL_GPL(ppp_channel_connection_register_notify);
|
|
+
|
|
+void ppp_channel_connection_unregister_notify(struct notifier_block *nb)
|
|
+{
|
|
+ raw_notifier_chain_unregister(&ppp_channel_connection_notifier_list, nb);
|
|
+}
|
|
+EXPORT_SYMBOL_GPL(ppp_channel_connection_unregister_notify);
|
|
+
|
|
/* Prototypes. */
|
|
static int ppp_unattached_ioctl(struct net *net, struct ppp_file *pf,
|
|
struct file *file, unsigned int cmd, unsigned long arg);
|
|
@@ -3468,6 +3486,7 @@ ppp_connect_channel(struct channel *pch,
|
|
struct ppp_net *pn;
|
|
int ret = -ENXIO;
|
|
int hdrlen;
|
|
+ int notify = 0;
|
|
|
|
pn = ppp_pernet(pch->chan_net);
|
|
|
|
@@ -3500,6 +3519,8 @@ ppp_connect_channel(struct channel *pch,
|
|
++ppp->n_channels;
|
|
pch->ppp = ppp;
|
|
refcount_inc(&ppp->file.refcnt);
|
|
+ notify = 1;
|
|
+
|
|
ppp_unlock(ppp);
|
|
ret = 0;
|
|
|
|
@@ -3507,6 +3528,14 @@ ppp_connect_channel(struct channel *pch,
|
|
write_unlock_bh(&pch->upl);
|
|
out:
|
|
mutex_unlock(&pn->all_ppp_mutex);
|
|
+
|
|
+ if (notify && ppp && ppp->dev) {
|
|
+ dev_hold(ppp->dev);
|
|
+ raw_notifier_call_chain(&ppp_channel_connection_notifier_list,
|
|
+ PPP_CHANNEL_CONNECT, ppp->dev);
|
|
+ dev_put(ppp->dev);
|
|
+ }
|
|
+
|
|
return ret;
|
|
}
|
|
|
|
@@ -3524,6 +3553,13 @@ ppp_disconnect_channel(struct channel *p
|
|
pch->ppp = NULL;
|
|
write_unlock_bh(&pch->upl);
|
|
if (ppp) {
|
|
+ if (ppp->dev) {
|
|
+ dev_hold(ppp->dev);
|
|
+ raw_notifier_call_chain(&ppp_channel_connection_notifier_list,
|
|
+ PPP_CHANNEL_DISCONNECT, ppp->dev);
|
|
+ dev_put(ppp->dev);
|
|
+ }
|
|
+
|
|
/* remove it from the ppp unit's list */
|
|
ppp_lock(ppp);
|
|
list_del(&pch->clist);
|
|
@@ -3603,6 +3639,188 @@ static void *unit_find(struct idr *p, in
|
|
return idr_find(p, n);
|
|
}
|
|
|
|
+/* Updates the PPP interface statistics. */
|
|
+void ppp_update_stats(struct net_device *dev, unsigned long rx_packets,
|
|
+ unsigned long rx_bytes, unsigned long tx_packets,
|
|
+ unsigned long tx_bytes, unsigned long rx_errors,
|
|
+ unsigned long tx_errors, unsigned long rx_dropped,
|
|
+ unsigned long tx_dropped)
|
|
+{
|
|
+ struct ppp *ppp;
|
|
+
|
|
+ if (!dev)
|
|
+ return;
|
|
+
|
|
+ if (dev->type != ARPHRD_PPP)
|
|
+ return;
|
|
+
|
|
+ ppp = netdev_priv(dev);
|
|
+
|
|
+ ppp_xmit_lock(ppp);
|
|
+ ppp->stats64.tx_packets += tx_packets;
|
|
+ ppp->stats64.tx_bytes += tx_bytes;
|
|
+ ppp->dev->stats.tx_errors += tx_errors;
|
|
+ ppp->dev->stats.tx_dropped += tx_dropped;
|
|
+ if (tx_packets)
|
|
+ ppp->last_xmit = jiffies;
|
|
+ ppp_xmit_unlock(ppp);
|
|
+
|
|
+ ppp_recv_lock(ppp);
|
|
+ ppp->stats64.rx_packets += rx_packets;
|
|
+ ppp->stats64.rx_bytes += rx_bytes;
|
|
+ ppp->dev->stats.rx_errors += rx_errors;
|
|
+ ppp->dev->stats.rx_dropped += rx_dropped;
|
|
+ if (rx_packets)
|
|
+ ppp->last_recv = jiffies;
|
|
+ ppp_recv_unlock(ppp);
|
|
+}
|
|
+
|
|
+/* Returns >0 if the device is a multilink PPP netdevice, 0 if not or < 0 if
|
|
+ * the device is not PPP.
|
|
+ */
|
|
+int ppp_is_multilink(struct net_device *dev)
|
|
+{
|
|
+ struct ppp *ppp;
|
|
+ unsigned int flags;
|
|
+
|
|
+ if (!dev)
|
|
+ return -1;
|
|
+
|
|
+ if (dev->type != ARPHRD_PPP)
|
|
+ return -1;
|
|
+
|
|
+ ppp = netdev_priv(dev);
|
|
+ ppp_lock(ppp);
|
|
+ flags = ppp->flags;
|
|
+ ppp_unlock(ppp);
|
|
+
|
|
+ if (flags & SC_MULTILINK)
|
|
+ return 1;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+EXPORT_SYMBOL(ppp_is_multilink);
|
|
+
|
|
+/* ppp_channel_get_protocol()
|
|
+ * Call this to obtain the underlying protocol of the PPP channel,
|
|
+ * e.g. PX_PROTO_OE
|
|
+ *
|
|
+ * NOTE: Some channels do not use PX sockets so the protocol value may be very
|
|
+ * different for them.
|
|
+ * NOTE: -1 indicates failure.
|
|
+ * NOTE: Once you know the channel protocol you may then either cast 'chan' to
|
|
+ * its sub-class or use the channel protocol specific API's as provided by that
|
|
+ * channel sub type.
|
|
+ */
|
|
+int ppp_channel_get_protocol(struct ppp_channel *chan)
|
|
+{
|
|
+ if (!chan->ops->get_channel_protocol)
|
|
+ return -1;
|
|
+
|
|
+ return chan->ops->get_channel_protocol(chan);
|
|
+}
|
|
+EXPORT_SYMBOL(ppp_channel_get_protocol);
|
|
+
|
|
+/* 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);
|
|
+
|
|
+/* ppp_hold_channels()
|
|
+ * Returns the PPP channels of the PPP device, storing each one into
|
|
+ * channels[].
|
|
+ *
|
|
+ * channels[] has chan_sz elements.
|
|
+ * This function returns the number of channels stored, up to chan_sz.
|
|
+ * It will return < 0 if the device is not PPP.
|
|
+ *
|
|
+ * You MUST release the channels using ppp_release_channels().
|
|
+ */
|
|
+int ppp_hold_channels(struct net_device *dev, struct ppp_channel *channels[],
|
|
+ unsigned int chan_sz)
|
|
+{
|
|
+ struct ppp *ppp;
|
|
+ int c;
|
|
+ struct channel *pch;
|
|
+
|
|
+ if (!dev)
|
|
+ return -1;
|
|
+
|
|
+ if (dev->type != ARPHRD_PPP)
|
|
+ return -1;
|
|
+
|
|
+ ppp = netdev_priv(dev);
|
|
+
|
|
+ c = 0;
|
|
+ ppp_lock(ppp);
|
|
+ list_for_each_entry(pch, &ppp->channels, clist) {
|
|
+ struct ppp_channel *chan;
|
|
+
|
|
+ if (!pch->chan) {
|
|
+ /* Channel is going / gone away */
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ if (c == chan_sz) {
|
|
+ /* No space to record channel */
|
|
+ ppp_unlock(ppp);
|
|
+ return c;
|
|
+ }
|
|
+
|
|
+ /* Hold the channel, if supported */
|
|
+ chan = pch->chan;
|
|
+ if (!chan->ops->hold)
|
|
+ continue;
|
|
+
|
|
+ chan->ops->hold(chan);
|
|
+
|
|
+ /* Record the channel */
|
|
+ channels[c++] = chan;
|
|
+ }
|
|
+ ppp_unlock(ppp);
|
|
+ return c;
|
|
+}
|
|
+EXPORT_SYMBOL(ppp_hold_channels);
|
|
+
|
|
+/* ppp_release_channels()
|
|
+ * Releases channels
|
|
+ */
|
|
+void ppp_release_channels(struct ppp_channel *channels[], unsigned int chan_sz)
|
|
+{
|
|
+ unsigned int c;
|
|
+
|
|
+ for (c = 0; c < chan_sz; ++c) {
|
|
+ struct ppp_channel *chan;
|
|
+
|
|
+ chan = channels[c];
|
|
+ chan->ops->release(chan);
|
|
+ }
|
|
+}
|
|
+EXPORT_SYMBOL(ppp_release_channels);
|
|
+
|
|
/* Module/initialization stuff */
|
|
|
|
module_init(ppp_init);
|
|
@@ -3619,6 +3837,8 @@ EXPORT_SYMBOL(ppp_input_error);
|
|
EXPORT_SYMBOL(ppp_output_wakeup);
|
|
EXPORT_SYMBOL(ppp_register_compressor);
|
|
EXPORT_SYMBOL(ppp_unregister_compressor);
|
|
+EXPORT_SYMBOL(ppp_update_stats);
|
|
+
|
|
MODULE_LICENSE("GPL");
|
|
MODULE_ALIAS_CHARDEV(PPP_MAJOR, 0);
|
|
MODULE_ALIAS_RTNL_LINK("ppp");
|
|
--- a/drivers/net/ppp/pppoe.c
|
|
+++ b/drivers/net/ppp/pppoe.c
|
|
@@ -62,6 +62,7 @@
|
|
#include <linux/inetdevice.h>
|
|
#include <linux/etherdevice.h>
|
|
#include <linux/skbuff.h>
|
|
+#include <linux/if_arp.h>
|
|
#include <linux/init.h>
|
|
#include <linux/if_ether.h>
|
|
#include <linux/if_pppox.h>
|
|
@@ -87,7 +88,7 @@
|
|
static int __pppoe_xmit(struct sock *sk, struct sk_buff *skb);
|
|
|
|
static const struct proto_ops pppoe_ops;
|
|
-static const struct ppp_channel_ops pppoe_chan_ops;
|
|
+static const struct pppoe_channel_ops pppoe_chan_ops;
|
|
|
|
/* per-net private data for this module */
|
|
static unsigned int pppoe_net_id __read_mostly;
|
|
@@ -645,6 +646,7 @@ static int pppoe_connect(struct socket *
|
|
if (stage_session(po->pppoe_pa.sid)) {
|
|
pppox_unbind_sock(sk);
|
|
pn = pppoe_pernet(sock_net(sk));
|
|
+
|
|
delete_item(pn, po->pppoe_pa.sid,
|
|
po->pppoe_pa.remote, po->pppoe_ifindex);
|
|
if (po->pppoe_dev) {
|
|
@@ -692,7 +694,7 @@ static int pppoe_connect(struct socket *
|
|
|
|
po->chan.mtu = dev->mtu - sizeof(struct pppoe_hdr) - 2;
|
|
po->chan.private = sk;
|
|
- po->chan.ops = &pppoe_chan_ops;
|
|
+ po->chan.ops = (struct ppp_channel_ops *)&pppoe_chan_ops;
|
|
|
|
error = ppp_register_net_channel(dev_net(dev), &po->chan);
|
|
if (error) {
|
|
@@ -995,9 +997,80 @@ static int pppoe_fill_forward_path(struc
|
|
return 0;
|
|
}
|
|
|
|
-static const struct ppp_channel_ops pppoe_chan_ops = {
|
|
- .start_xmit = pppoe_xmit,
|
|
- .fill_forward_path = pppoe_fill_forward_path,
|
|
+/************************************************************************
|
|
+ *
|
|
+ * function called by generic PPP driver to hold channel
|
|
+ *
|
|
+ ***********************************************************************/
|
|
+static void pppoe_hold_chan(struct ppp_channel *chan)
|
|
+{
|
|
+ struct sock *sk = (struct sock *)chan->private;
|
|
+
|
|
+ sock_hold(sk);
|
|
+}
|
|
+
|
|
+/************************************************************************
|
|
+ *
|
|
+ * function called by generic PPP driver to release channel
|
|
+ *
|
|
+ ***********************************************************************/
|
|
+static void pppoe_release_chan(struct ppp_channel *chan)
|
|
+{
|
|
+ struct sock *sk = (struct sock *)chan->private;
|
|
+
|
|
+ sock_put(sk);
|
|
+}
|
|
+
|
|
+/************************************************************************
|
|
+ *
|
|
+ * function called to get the channel protocol type
|
|
+ *
|
|
+ ***********************************************************************/
|
|
+static int pppoe_get_channel_protocol(struct ppp_channel *chan)
|
|
+{
|
|
+ return PX_PROTO_OE;
|
|
+}
|
|
+
|
|
+/************************************************************************
|
|
+ *
|
|
+ * function called to get the PPPoE channel addressing
|
|
+ * NOTE: This function returns a HOLD to the netdevice
|
|
+ *
|
|
+ ***********************************************************************/
|
|
+static int pppoe_get_addressing(struct ppp_channel *chan,
|
|
+ struct pppoe_opt *addressing)
|
|
+{
|
|
+ struct sock *sk = (struct sock *)chan->private;
|
|
+ struct pppox_sock *po = pppox_sk(sk);
|
|
+ int err = 0;
|
|
+
|
|
+ *addressing = po->proto.pppoe;
|
|
+ if (!addressing->dev)
|
|
+ return -ENODEV;
|
|
+
|
|
+ dev_hold(addressing->dev);
|
|
+ return err;
|
|
+}
|
|
+
|
|
+/* pppoe_channel_addressing_get()
|
|
+ * Return PPPoE channel specific addressing information.
|
|
+ */
|
|
+int pppoe_channel_addressing_get(struct ppp_channel *chan,
|
|
+ struct pppoe_opt *addressing)
|
|
+{
|
|
+ return pppoe_get_addressing(chan, addressing);
|
|
+}
|
|
+EXPORT_SYMBOL(pppoe_channel_addressing_get);
|
|
+
|
|
+static const struct pppoe_channel_ops pppoe_chan_ops = {
|
|
+ /* PPPoE specific channel ops */
|
|
+ .get_addressing = pppoe_get_addressing,
|
|
+ /* General ppp channel ops */
|
|
+ .ops.start_xmit = pppoe_xmit,
|
|
+ .ops.fill_forward_path = pppoe_fill_forward_path,
|
|
+ .ops.get_channel_protocol = pppoe_get_channel_protocol,
|
|
+ .ops.hold = pppoe_hold_chan,
|
|
+ .ops.release = pppoe_release_chan,
|
|
};
|
|
|
|
static int pppoe_recvmsg(struct socket *sock, struct msghdr *m,
|
|
--- a/include/linux/if_pppox.h
|
|
+++ b/include/linux/if_pppox.h
|
|
@@ -1,11 +1,12 @@
|
|
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
/***************************************************************************
|
|
* Linux PPP over X - Generic PPP transport layer sockets
|
|
- * Linux PPP over Ethernet (PPPoE) Socket Implementation (RFC 2516)
|
|
+ * Linux PPP over Ethernet (PPPoE) Socket Implementation (RFC 2516)
|
|
*
|
|
* This file supplies definitions required by the PPP over Ethernet driver
|
|
* (pppox.c). All version information wrt this file is located in pppox.c
|
|
*/
|
|
+
|
|
#ifndef __LINUX_IF_PPPOX_H
|
|
#define __LINUX_IF_PPPOX_H
|
|
|
|
@@ -91,4 +92,17 @@ enum {
|
|
PPPOX_DEAD = 16 /* dead, useless, please clean me up!*/
|
|
};
|
|
|
|
+/*
|
|
+ * PPPoE Channel specific operations
|
|
+ */
|
|
+struct pppoe_channel_ops {
|
|
+ /* Must be first - general to all PPP channels */
|
|
+ struct ppp_channel_ops ops;
|
|
+ int (*get_addressing)(struct ppp_channel *, struct pppoe_opt *);
|
|
+};
|
|
+
|
|
+/* Return PPPoE channel specific addressing information */
|
|
+extern int pppoe_channel_addressing_get(struct ppp_channel *chan,
|
|
+ struct pppoe_opt *addressing);
|
|
+
|
|
#endif /* !(__LINUX_IF_PPPOX_H) */
|
|
--- a/include/linux/ppp_channel.h
|
|
+++ b/include/linux/ppp_channel.h
|
|
@@ -19,6 +19,11 @@
|
|
#include <linux/skbuff.h>
|
|
#include <linux/poll.h>
|
|
#include <net/net_namespace.h>
|
|
+#include <linux/notifier.h>
|
|
+
|
|
+/* PPP channel connection event types */
|
|
+#define PPP_CHANNEL_DISCONNECT 0
|
|
+#define PPP_CHANNEL_CONNECT 1
|
|
|
|
struct net_device_path;
|
|
struct net_device_path_ctx;
|
|
@@ -33,6 +38,15 @@ struct ppp_channel_ops {
|
|
int (*fill_forward_path)(struct net_device_path_ctx *,
|
|
struct net_device_path *,
|
|
const struct ppp_channel *);
|
|
+
|
|
+ /* Get channel protocol type, one of PX_PROTO_XYZ or specific to
|
|
+ * the channel subtype
|
|
+ */
|
|
+ int (*get_channel_protocol)(struct ppp_channel *);
|
|
+ /* Hold the channel from being destroyed */
|
|
+ void (*hold)(struct ppp_channel *);
|
|
+ /* Release hold on the channel */
|
|
+ void (*release)(struct ppp_channel *);
|
|
};
|
|
|
|
struct ppp_channel {
|
|
@@ -47,6 +61,38 @@ struct ppp_channel {
|
|
};
|
|
|
|
#ifdef __KERNEL__
|
|
+/* Call this to obtain the underlying protocol of the PPP channel,
|
|
+ * e.g. PX_PROTO_OE
|
|
+ */
|
|
+extern int ppp_channel_get_protocol(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);
|
|
+
|
|
+/* Hold PPP channels for the PPP device */
|
|
+extern int ppp_hold_channels(struct net_device *dev,
|
|
+ struct ppp_channel *channels[],
|
|
+ unsigned int chan_sz);
|
|
+
|
|
+/* Test if the ppp device is a multi-link ppp device */
|
|
+extern int ppp_is_multilink(struct net_device *dev);
|
|
+
|
|
+/* Update statistics of the PPP net_device by incrementing related
|
|
+ * statistics field value with corresponding parameter
|
|
+ */
|
|
+extern void ppp_update_stats(struct net_device *dev, unsigned long rx_packets,
|
|
+ unsigned long rx_bytes, unsigned long tx_packets,
|
|
+ unsigned long tx_bytes, unsigned long rx_errors,
|
|
+ unsigned long tx_errors, unsigned long rx_dropped,
|
|
+ unsigned long tx_dropped);
|
|
+
|
|
/* Called by the channel when it can send some more data. */
|
|
extern void ppp_output_wakeup(struct ppp_channel *);
|
|
|
|
@@ -76,6 +122,12 @@ extern int ppp_unit_number(struct ppp_ch
|
|
/* Get the device name associated with a channel, or NULL if none */
|
|
extern char *ppp_dev_name(struct ppp_channel *);
|
|
|
|
+/* Register the PPP channel connect notifier */
|
|
+extern void ppp_channel_connection_register_notify(struct notifier_block *nb);
|
|
+
|
|
+/* Unregister the PPP channel connect notifier */
|
|
+extern void ppp_channel_connection_unregister_notify(struct notifier_block *nb);
|
|
+
|
|
/*
|
|
* SMP locking notes:
|
|
* The channel code must ensure that when it calls ppp_unregister_channel,
|
|
--- a/net/l2tp/l2tp_core.c
|
|
+++ b/net/l2tp/l2tp_core.c
|
|
@@ -403,6 +403,30 @@ err_tlock:
|
|
}
|
|
EXPORT_SYMBOL_GPL(l2tp_session_register);
|
|
|
|
+void l2tp_stats_update(struct l2tp_tunnel *tunnel,
|
|
+ struct l2tp_session *session,
|
|
+ struct l2tp_stats *stats)
|
|
+{
|
|
+ atomic_long_add(atomic_long_read(&stats->rx_packets),
|
|
+ &tunnel->stats.rx_packets);
|
|
+ atomic_long_add(atomic_long_read(&stats->rx_bytes),
|
|
+ &tunnel->stats.rx_bytes);
|
|
+ atomic_long_add(atomic_long_read(&stats->tx_packets),
|
|
+ &tunnel->stats.tx_packets);
|
|
+ atomic_long_add(atomic_long_read(&stats->tx_bytes),
|
|
+ &tunnel->stats.tx_bytes);
|
|
+
|
|
+ atomic_long_add(atomic_long_read(&stats->rx_packets),
|
|
+ &session->stats.rx_packets);
|
|
+ atomic_long_add(atomic_long_read(&stats->rx_bytes),
|
|
+ &session->stats.rx_bytes);
|
|
+ atomic_long_add(atomic_long_read(&stats->tx_packets),
|
|
+ &session->stats.tx_packets);
|
|
+ atomic_long_add(atomic_long_read(&stats->tx_bytes),
|
|
+ &session->stats.tx_bytes);
|
|
+}
|
|
+EXPORT_SYMBOL_GPL(l2tp_stats_update);
|
|
+
|
|
/*****************************************************************************
|
|
* Receive data handling
|
|
*****************************************************************************/
|
|
--- a/net/l2tp/l2tp_core.h
|
|
+++ b/net/l2tp/l2tp_core.h
|
|
@@ -231,6 +231,8 @@ struct l2tp_session *l2tp_session_get(co
|
|
struct l2tp_session *l2tp_session_get_nth(struct l2tp_tunnel *tunnel, int nth);
|
|
struct l2tp_session *l2tp_session_get_by_ifname(const struct net *net,
|
|
const char *ifname);
|
|
+void l2tp_stats_update(struct l2tp_tunnel *tunnel, struct l2tp_session *session,
|
|
+ struct l2tp_stats *stats);
|
|
|
|
/* Tunnel and session lifetime management.
|
|
* Creation of a new instance is a two-step process: create, then register.
|