Commit 3557baab authored by James Chapman's avatar James Chapman Committed by David S. Miller

[L2TP]: PPP over L2TP driver core

This driver handles only L2TP data frames; control frames are handled
by a userspace application. It implements L2TP using the PPPoX socket
family. There is a PPPoX socket for each L2TP session in an L2TP
tunnel.  PPP data within each session is passed through the kernel's
PPP subsystem via this driver. Kernel parameters of each socket can be
read or modified using ioctl() or [gs]etsockopt() calls.
Signed-off-by: default avatarJames Chapman <jchapman@katalix.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent cf14a4d0
......@@ -2784,6 +2784,19 @@ config PPPOATM
which can lead to bad results if the ATM peer loses state and
changes its encapsulation unilaterally.
config PPPOL2TP
tristate "PPP over L2TP (EXPERIMENTAL)"
depends on EXPERIMENTAL && PPP
help
Support for PPP-over-L2TP socket family. L2TP is a protocol
used by ISPs and enterprises to tunnel PPP traffic over UDP
tunnels. L2TP is replacing PPTP for VPN uses.
This kernel component handles only L2TP data packets: a
userland daemon handles L2TP the control protocol (tunnel
and session setup). One such daemon is OpenL2TP
(http://openl2tp.sourceforge.net/).
config SLIP
tristate "SLIP (serial line) support"
---help---
......
......@@ -121,6 +121,7 @@ obj-$(CONFIG_PPP_DEFLATE) += ppp_deflate.o
obj-$(CONFIG_PPP_BSDCOMP) += bsd_comp.o
obj-$(CONFIG_PPP_MPPE) += ppp_mppe.o
obj-$(CONFIG_PPPOE) += pppox.o pppoe.o
obj-$(CONFIG_PPPOL2TP) += pppox.o pppol2tp.o
obj-$(CONFIG_SLIP) += slip.o
obj-$(CONFIG_SLHC) += slhc.o
......
/*****************************************************************************
* Linux PPP over L2TP (PPPoX/PPPoL2TP) Sockets
*
* PPPoX --- Generic PPP encapsulation socket family
* PPPoL2TP --- PPP over L2TP (RFC 2661)
*
* Version: 1.0.0
*
* Authors: Martijn van Oosterhout <kleptog@svana.org>
* James Chapman (jchapman@katalix.com)
* Contributors:
* Michal Ostrowski <mostrows@speakeasy.net>
* Arnaldo Carvalho de Melo <acme@xconectiva.com.br>
* David S. Miller (davem@redhat.com)
*
* License:
* 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.
*
*/
/* This driver handles only L2TP data frames; control frames are handled by a
* userspace application.
*
* To send data in an L2TP session, userspace opens a PPPoL2TP socket and
* attaches it to a bound UDP socket with local tunnel_id / session_id and
* peer tunnel_id / session_id set. Data can then be sent or received using
* regular socket sendmsg() / recvmsg() calls. Kernel parameters of the socket
* can be read or modified using ioctl() or [gs]etsockopt() calls.
*
* When a PPPoL2TP socket is connected with local and peer session_id values
* zero, the socket is treated as a special tunnel management socket.
*
* Here's example userspace code to create a socket for sending/receiving data
* over an L2TP session:-
*
* struct sockaddr_pppol2tp sax;
* int fd;
* int session_fd;
*
* fd = socket(AF_PPPOX, SOCK_DGRAM, PX_PROTO_OL2TP);
*
* sax.sa_family = AF_PPPOX;
* sax.sa_protocol = PX_PROTO_OL2TP;
* sax.pppol2tp.fd = tunnel_fd; // bound UDP socket
* sax.pppol2tp.addr.sin_addr.s_addr = addr->sin_addr.s_addr;
* sax.pppol2tp.addr.sin_port = addr->sin_port;
* sax.pppol2tp.addr.sin_family = AF_INET;
* sax.pppol2tp.s_tunnel = tunnel_id;
* sax.pppol2tp.s_session = session_id;
* sax.pppol2tp.d_tunnel = peer_tunnel_id;
* sax.pppol2tp.d_session = peer_session_id;
*
* session_fd = connect(fd, (struct sockaddr *)&sax, sizeof(sax));
*
* A pppd plugin that allows PPP traffic to be carried over L2TP using
* this driver is available from the OpenL2TP project at
* http://openl2tp.sourceforge.net.
*/
#include <linux/module.h>
#include <linux/version.h>
#include <linux/string.h>
#include <linux/list.h>
#include <asm/uaccess.h>
#include <linux/kernel.h>
#include <linux/spinlock.h>
#include <linux/kthread.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/jiffies.h>
#include <linux/netdevice.h>
#include <linux/net.h>
#include <linux/inetdevice.h>
#include <linux/skbuff.h>
#include <linux/init.h>
#include <linux/ip.h>
#include <linux/udp.h>
#include <linux/if_pppox.h>
#include <linux/if_pppol2tp.h>
#include <net/sock.h>
#include <linux/ppp_channel.h>
#include <linux/ppp_defs.h>
#include <linux/if_ppp.h>
#include <linux/file.h>
#include <linux/hash.h>
#include <linux/sort.h>
#include <linux/proc_fs.h>
#include <net/dst.h>
#include <net/ip.h>
#include <net/udp.h>
#include <net/xfrm.h>
#include <asm/byteorder.h>
#include <asm/atomic.h>
#define PPPOL2TP_DRV_VERSION "V1.0"
/* L2TP header constants */
#define L2TP_HDRFLAG_T 0x8000
#define L2TP_HDRFLAG_L 0x4000
#define L2TP_HDRFLAG_S 0x0800
#define L2TP_HDRFLAG_O 0x0200
#define L2TP_HDRFLAG_P 0x0100
#define L2TP_HDR_VER_MASK 0x000F
#define L2TP_HDR_VER 0x0002
/* Space for UDP, L2TP and PPP headers */
#define PPPOL2TP_HEADER_OVERHEAD 40
/* Just some random numbers */
#define L2TP_TUNNEL_MAGIC 0x42114DDA
#define L2TP_SESSION_MAGIC 0x0C04EB7D
#define PPPOL2TP_HASH_BITS 4
#define PPPOL2TP_HASH_SIZE (1 << PPPOL2TP_HASH_BITS)
/* Default trace flags */
#define PPPOL2TP_DEFAULT_DEBUG_FLAGS 0
#define PRINTK(_mask, _type, _lvl, _fmt, args...) \
do { \
if ((_mask) & (_type)) \
printk(_lvl "PPPOL2TP: " _fmt, ##args); \
} while(0)
/* Number of bytes to build transmit L2TP headers.
* Unfortunately the size is different depending on whether sequence numbers
* are enabled.
*/
#define PPPOL2TP_L2TP_HDR_SIZE_SEQ 10
#define PPPOL2TP_L2TP_HDR_SIZE_NOSEQ 6
struct pppol2tp_tunnel;
/* Describes a session. It is the sk_user_data field in the PPPoL2TP
* socket. Contains information to determine incoming packets and transmit
* outgoing ones.
*/
struct pppol2tp_session
{
int magic; /* should be
* L2TP_SESSION_MAGIC */
int owner; /* pid that opened the socket */
struct sock *sock; /* Pointer to the session
* PPPoX socket */
struct sock *tunnel_sock; /* Pointer to the tunnel UDP
* socket */
struct pppol2tp_addr tunnel_addr; /* Description of tunnel */
struct pppol2tp_tunnel *tunnel; /* back pointer to tunnel
* context */
char name[20]; /* "sess xxxxx/yyyyy", where
* x=tunnel_id, y=session_id */
int mtu;
int mru;
int flags; /* accessed by PPPIOCGFLAGS.
* Unused. */
unsigned recv_seq:1; /* expect receive packets with
* sequence numbers? */
unsigned send_seq:1; /* send packets with sequence
* numbers? */
unsigned lns_mode:1; /* behave as LNS? LAC enables
* sequence numbers under
* control of LNS. */
int debug; /* bitmask of debug message
* categories */
int reorder_timeout; /* configured reorder timeout
* (in jiffies) */
u16 nr; /* session NR state (receive) */
u16 ns; /* session NR state (send) */
struct sk_buff_head reorder_q; /* receive reorder queue */
struct pppol2tp_ioc_stats stats;
struct hlist_node hlist; /* Hash list node */
};
/* The sk_user_data field of the tunnel's UDP socket. It contains info to track
* all the associated sessions so incoming packets can be sorted out
*/
struct pppol2tp_tunnel
{
int magic; /* Should be L2TP_TUNNEL_MAGIC */
rwlock_t hlist_lock; /* protect session_hlist */
struct hlist_head session_hlist[PPPOL2TP_HASH_SIZE];
/* hashed list of sessions,
* hashed by id */
int debug; /* bitmask of debug message
* categories */
char name[12]; /* "tunl xxxxx" */
struct pppol2tp_ioc_stats stats;
void (*old_sk_destruct)(struct sock *);
struct sock *sock; /* Parent socket */
struct list_head list; /* Keep a list of all open
* prepared sockets */
atomic_t ref_count;
};
/* Private data stored for received packets in the skb.
*/
struct pppol2tp_skb_cb {
u16 ns;
u16 nr;
u16 has_seq;
u16 length;
unsigned long expires;
};
#define PPPOL2TP_SKB_CB(skb) ((struct pppol2tp_skb_cb *) &skb->cb[sizeof(struct inet_skb_parm)])
static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb);
static void pppol2tp_tunnel_free(struct pppol2tp_tunnel *tunnel);
static atomic_t pppol2tp_tunnel_count;
static atomic_t pppol2tp_session_count;
static struct ppp_channel_ops pppol2tp_chan_ops = { pppol2tp_xmit , NULL };
static struct proto_ops pppol2tp_ops;
static LIST_HEAD(pppol2tp_tunnel_list);
static DEFINE_RWLOCK(pppol2tp_tunnel_list_lock);
/* Helpers to obtain tunnel/session contexts from sockets.
*/
static inline struct pppol2tp_session *pppol2tp_sock_to_session(struct sock *sk)
{
struct pppol2tp_session *session;
if (sk == NULL)
return NULL;
session = (struct pppol2tp_session *)(sk->sk_user_data);
if (session == NULL)
return NULL;
BUG_ON(session->magic != L2TP_SESSION_MAGIC);
return session;
}
static inline struct pppol2tp_tunnel *pppol2tp_sock_to_tunnel(struct sock *sk)
{
struct pppol2tp_tunnel *tunnel;
if (sk == NULL)
return NULL;
tunnel = (struct pppol2tp_tunnel *)(sk->sk_user_data);
if (tunnel == NULL)
return NULL;
BUG_ON(tunnel->magic != L2TP_TUNNEL_MAGIC);
return tunnel;
}
/* Tunnel reference counts. Incremented per session that is added to
* the tunnel.
*/
static inline void pppol2tp_tunnel_inc_refcount(struct pppol2tp_tunnel *tunnel)
{
atomic_inc(&tunnel->ref_count);
}
static inline void pppol2tp_tunnel_dec_refcount(struct pppol2tp_tunnel *tunnel)
{
if (atomic_dec_and_test(&tunnel->ref_count))
pppol2tp_tunnel_free(tunnel);
}
/* Session hash list.
* The session_id SHOULD be random according to RFC2661, but several
* L2TP implementations (Cisco and Microsoft) use incrementing
* session_ids. So we do a real hash on the session_id, rather than a
* simple bitmask.
*/
static inline struct hlist_head *
pppol2tp_session_id_hash(struct pppol2tp_tunnel *tunnel, u16 session_id)
{
unsigned long hash_val = (unsigned long) session_id;
return &tunnel->session_hlist[hash_long(hash_val, PPPOL2TP_HASH_BITS)];
}
/* Lookup a session by id
*/
static struct pppol2tp_session *
pppol2tp_session_find(struct pppol2tp_tunnel *tunnel, u16 session_id)
{
struct hlist_head *session_list =
pppol2tp_session_id_hash(tunnel, session_id);
struct pppol2tp_session *session;
struct hlist_node *walk;
read_lock(&tunnel->hlist_lock);
hlist_for_each_entry(session, walk, session_list, hlist) {
if (session->tunnel_addr.s_session == session_id) {
read_unlock(&tunnel->hlist_lock);
return session;
}
}
read_unlock(&tunnel->hlist_lock);
return NULL;
}
/* Lookup a tunnel by id
*/
static struct pppol2tp_tunnel *pppol2tp_tunnel_find(u16 tunnel_id)
{
struct pppol2tp_tunnel *tunnel = NULL;
read_lock(&pppol2tp_tunnel_list_lock);
list_for_each_entry(tunnel, &pppol2tp_tunnel_list, list) {
if (tunnel->stats.tunnel_id == tunnel_id) {
read_unlock(&pppol2tp_tunnel_list_lock);
return tunnel;
}
}
read_unlock(&pppol2tp_tunnel_list_lock);
return NULL;
}
/*****************************************************************************
* Receive data handling
*****************************************************************************/
/* Queue a skb in order. We come here only if the skb has an L2TP sequence
* number.
*/
static void pppol2tp_recv_queue_skb(struct pppol2tp_session *session, struct sk_buff *skb)
{
struct sk_buff *skbp;
u16 ns = PPPOL2TP_SKB_CB(skb)->ns;
spin_lock(&session->reorder_q.lock);
skb_queue_walk(&session->reorder_q, skbp) {
if (PPPOL2TP_SKB_CB(skbp)->ns > ns) {
__skb_insert(skb, skbp->prev, skbp, &session->reorder_q);
PRINTK(session->debug, PPPOL2TP_MSG_SEQ, KERN_DEBUG,
"%s: pkt %hu, inserted before %hu, reorder_q len=%d\n",
session->name, ns, PPPOL2TP_SKB_CB(skbp)->ns,
skb_queue_len(&session->reorder_q));
session->stats.rx_oos_packets++;
goto out;
}
}
__skb_queue_tail(&session->reorder_q, skb);
out:
spin_unlock(&session->reorder_q.lock);
}
/* Dequeue a single skb.
*/
static void pppol2tp_recv_dequeue_skb(struct pppol2tp_session *session, struct sk_buff *skb)
{
struct pppol2tp_tunnel *tunnel = session->tunnel;
int length = PPPOL2TP_SKB_CB(skb)->length;
struct sock *session_sock = NULL;
/* We're about to requeue the skb, so unlink it and return resources
* to its current owner (a socket receive buffer).
*/
skb_unlink(skb, &session->reorder_q);
skb_orphan(skb);
tunnel->stats.rx_packets++;
tunnel->stats.rx_bytes += length;
session->stats.rx_packets++;
session->stats.rx_bytes += length;
if (PPPOL2TP_SKB_CB(skb)->has_seq) {
/* Bump our Nr */
session->nr++;
PRINTK(session->debug, PPPOL2TP_MSG_SEQ, KERN_DEBUG,
"%s: updated nr to %hu\n", session->name, session->nr);
}
/* If the socket is bound, send it in to PPP's input queue. Otherwise
* queue it on the session socket.
*/
session_sock = session->sock;
if (session_sock->sk_state & PPPOX_BOUND) {
struct pppox_sock *po;
PRINTK(session->debug, PPPOL2TP_MSG_DATA, KERN_DEBUG,
"%s: recv %d byte data frame, passing to ppp\n",
session->name, length);
/* We need to forget all info related to the L2TP packet
* gathered in the skb as we are going to reuse the same
* skb for the inner packet.
* Namely we need to:
* - reset xfrm (IPSec) information as it applies to
* the outer L2TP packet and not to the inner one
* - release the dst to force a route lookup on the inner
* IP packet since skb->dst currently points to the dst
* of the UDP tunnel
* - reset netfilter information as it doesn't apply
* to the inner packet either
*/
secpath_reset(skb);
dst_release(skb->dst);
skb->dst = NULL;
nf_reset(skb);
po = pppox_sk(session_sock);
ppp_input(&po->chan, skb);
} else {
PRINTK(session->debug, PPPOL2TP_MSG_DATA, KERN_INFO,
"%s: socket not bound\n", session->name);
/* Not bound. Nothing we can do, so discard. */
session->stats.rx_errors++;
kfree_skb(skb);
}
sock_put(session->sock);
}
/* Dequeue skbs from the session's reorder_q, subject to packet order.
* Skbs that have been in the queue for too long are simply discarded.
*/
static void pppol2tp_recv_dequeue(struct pppol2tp_session *session)
{
struct sk_buff *skb;
struct sk_buff *tmp;
/* If the pkt at the head of the queue has the nr that we
* expect to send up next, dequeue it and any other
* in-sequence packets behind it.
*/
spin_lock(&session->reorder_q.lock);
skb_queue_walk_safe(&session->reorder_q, skb, tmp) {
if (time_after(jiffies, PPPOL2TP_SKB_CB(skb)->expires)) {
session->stats.rx_seq_discards++;
session->stats.rx_errors++;
PRINTK(session->debug, PPPOL2TP_MSG_SEQ, KERN_DEBUG,
"%s: oos pkt %hu len %d discarded (too old), "
"waiting for %hu, reorder_q_len=%d\n",
session->name, PPPOL2TP_SKB_CB(skb)->ns,
PPPOL2TP_SKB_CB(skb)->length, session->nr,
skb_queue_len(&session->reorder_q));
__skb_unlink(skb, &session->reorder_q);
kfree_skb(skb);
continue;
}
if (PPPOL2TP_SKB_CB(skb)->has_seq) {
if (PPPOL2TP_SKB_CB(skb)->ns != session->nr) {
PRINTK(session->debug, PPPOL2TP_MSG_SEQ, KERN_DEBUG,
"%s: holding oos pkt %hu len %d, "
"waiting for %hu, reorder_q_len=%d\n",
session->name, PPPOL2TP_SKB_CB(skb)->ns,
PPPOL2TP_SKB_CB(skb)->length, session->nr,
skb_queue_len(&session->reorder_q));
goto out;
}
}
spin_unlock(&session->reorder_q.lock);
pppol2tp_recv_dequeue_skb(session, skb);
spin_lock(&session->reorder_q.lock);
}
out:
spin_unlock(&session->reorder_q.lock);
}
/* Internal receive frame. Do the real work of receiving an L2TP data frame
* here. The skb is not on a list when we get here.
* Returns 0 if the packet was a data packet and was successfully passed on.
* Returns 1 if the packet was not a good data packet and could not be
* forwarded. All such packets are passed up to userspace to deal with.
*/
static int pppol2tp_recv_core(struct sock *sock, struct sk_buff *skb)
{
struct pppol2tp_session *session = NULL;
struct pppol2tp_tunnel *tunnel;
unsigned char *ptr;
u16 hdrflags;
u16 tunnel_id, session_id;
int length;
struct udphdr *uh;
tunnel = pppol2tp_sock_to_tunnel(sock);
if (tunnel == NULL)
goto error;
/* Short packet? */
if (skb->len < sizeof(struct udphdr)) {
PRINTK(tunnel->debug, PPPOL2TP_MSG_DATA, KERN_INFO,
"%s: recv short packet (len=%d)\n", tunnel->name, skb->len);
goto error;
}
/* Point to L2TP header */
ptr = skb->data + sizeof(struct udphdr);
/* Get L2TP header flags */
hdrflags = ntohs(*(__be16*)ptr);
/* Trace packet contents, if enabled */
if (tunnel->debug & PPPOL2TP_MSG_DATA) {
printk(KERN_DEBUG "%s: recv: ", tunnel->name);
for (length = 0; length < 16; length++)
printk(" %02X", ptr[length]);
printk("\n");
}
/* Get length of L2TP packet */
uh = (struct udphdr *) skb_transport_header(skb);
length = ntohs(uh->len) - sizeof(struct udphdr);
/* Too short? */
if (length < 12) {
PRINTK(tunnel->debug, PPPOL2TP_MSG_DATA, KERN_INFO,
"%s: recv short L2TP packet (len=%d)\n", tunnel->name, length);
goto error;
}
/* If type is control packet, it is handled by userspace. */
if (hdrflags & L2TP_HDRFLAG_T) {
PRINTK(tunnel->debug, PPPOL2TP_MSG_DATA, KERN_DEBUG,
"%s: recv control packet, len=%d\n", tunnel->name, length);
goto error;
}
/* Skip flags */
ptr += 2;
/* If length is present, skip it */
if (hdrflags & L2TP_HDRFLAG_L)
ptr += 2;
/* Extract tunnel and session ID */
tunnel_id = ntohs(*(__be16 *) ptr);
ptr += 2;
session_id = ntohs(*(__be16 *) ptr);
ptr += 2;
/* Find the session context */
session = pppol2tp_session_find(tunnel, session_id);
if (!session) {
/* Not found? Pass to userspace to deal with */
PRINTK(tunnel->debug, PPPOL2TP_MSG_DATA, KERN_INFO,
"%s: no socket found (%hu/%hu). Passing up.\n",
tunnel->name, tunnel_id, session_id);
goto error;
}
sock_hold(session->sock);
/* The ref count on the socket was increased by the above call since
* we now hold a pointer to the session. Take care to do sock_put()
* when exiting this function from now on...
*/
/* Handle the optional sequence numbers. If we are the LAC,
* enable/disable sequence numbers under the control of the LNS. If
* no sequence numbers present but we were expecting them, discard
* frame.
*/
if (hdrflags & L2TP_HDRFLAG_S) {
u16 ns, nr;
ns = ntohs(*(__be16 *) ptr);
ptr += 2;
nr = ntohs(*(__be16 *) ptr);
ptr += 2;
/* Received a packet with sequence numbers. If we're the LNS,
* check if we sre sending sequence numbers and if not,
* configure it so.
*/
if ((!session->lns_mode) && (!session->send_seq)) {
PRINTK(session->debug, PPPOL2TP_MSG_SEQ, KERN_INFO,
"%s: requested to enable seq numbers by LNS\n",
session->name);
session->send_seq = -1;
}
/* Store L2TP info in the skb */
PPPOL2TP_SKB_CB(skb)->ns = ns;
PPPOL2TP_SKB_CB(skb)->nr = nr;
PPPOL2TP_SKB_CB(skb)->has_seq = 1;
PRINTK(session->debug, PPPOL2TP_MSG_SEQ, KERN_DEBUG,
"%s: recv data ns=%hu, nr=%hu, session nr=%hu\n",
session->name, ns, nr, session->nr);
} else {
/* No sequence numbers.
* If user has configured mandatory sequence numbers, discard.
*/
if (session->recv_seq) {
PRINTK(session->debug, PPPOL2TP_MSG_SEQ, KERN_WARNING,
"%s: recv data has no seq numbers when required. "
"Discarding\n", session->name);
session->stats.rx_seq_discards++;
session->stats.rx_errors++;
goto discard;
}
/* If we're the LAC and we're sending sequence numbers, the
* LNS has requested that we no longer send sequence numbers.
* If we're the LNS and we're sending sequence numbers, the
* LAC is broken. Discard the frame.
*/
if ((!session->lns_mode) && (session->send_seq)) {
PRINTK(session->debug, PPPOL2TP_MSG_SEQ, KERN_INFO,
"%s: requested to disable seq numbers by LNS\n",
session->name);
session->send_seq = 0;
} else if (session->send_seq) {
PRINTK(session->debug, PPPOL2TP_MSG_SEQ, KERN_WARNING,
"%s: recv data has no seq numbers when required. "
"Discarding\n", session->name);
session->stats.rx_seq_discards++;
session->stats.rx_errors++;
goto discard;
}
/* Store L2TP info in the skb */
PPPOL2TP_SKB_CB(skb)->has_seq = 0;
}
/* If offset bit set, skip it. */
if (hdrflags & L2TP_HDRFLAG_O)
ptr += 2 + ntohs(*(__be16 *) ptr);
skb_pull(skb, ptr - skb->data);
/* Skip PPP header, if present. In testing, Microsoft L2TP clients
* don't send the PPP header (PPP header compression enabled), but
* other clients can include the header. So we cope with both cases
* here. The PPP header is always FF03 when using L2TP.
*
* Note that skb->data[] isn't dereferenced from a u16 ptr here since
* the field may be unaligned.
*/
if ((skb->data[0] == 0xff) && (skb->data[1] == 0x03))
skb_pull(skb, 2);
/* Prepare skb for adding to the session's reorder_q. Hold
* packets for max reorder_timeout or 1 second if not
* reordering.
*/
PPPOL2TP_SKB_CB(skb)->length = length;
PPPOL2TP_SKB_CB(skb)->expires = jiffies +
(session->reorder_timeout ? session->reorder_timeout : HZ);
/* Add packet to the session's receive queue. Reordering is done here, if
* enabled. Saved L2TP protocol info is stored in skb->sb[].
*/
if (PPPOL2TP_SKB_CB(skb)->has_seq) {
if (session->reorder_timeout != 0) {
/* Packet reordering enabled. Add skb to session's
* reorder queue, in order of ns.
*/
pppol2tp_recv_queue_skb(session, skb);
} else {
/* Packet reordering disabled. Discard out-of-sequence
* packets
*/
if (PPPOL2TP_SKB_CB(skb)->ns != session->nr) {
session->stats.rx_seq_discards++;
session->stats.rx_errors++;
PRINTK(session->debug, PPPOL2TP_MSG_SEQ, KERN_DEBUG,
"%s: oos pkt %hu len %d discarded, "
"waiting for %hu, reorder_q_len=%d\n",
session->name, PPPOL2TP_SKB_CB(skb)->ns,
PPPOL2TP_SKB_CB(skb)->length, session->nr,
skb_queue_len(&session->reorder_q));
goto discard;
}
skb_queue_tail(&session->reorder_q, skb);
}
} else {
/* No sequence numbers. Add the skb to the tail of the
* reorder queue. This ensures that it will be
* delivered after all previous sequenced skbs.
*/
skb_queue_tail(&session->reorder_q, skb);
}
/* Try to dequeue as many skbs from reorder_q as we can. */
pppol2tp_recv_dequeue(session);
return 0;
discard:
kfree_skb(skb);
sock_put(session->sock);
return 0;
error:
return 1;
}
/* UDP encapsulation receive handler. See net/ipv4/udp.c.
* Return codes:
* 0 : success.
* <0: error
* >0: skb should be passed up to userspace as UDP.
*/
static int pppol2tp_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
{
struct pppol2tp_tunnel *tunnel;
tunnel = pppol2tp_sock_to_tunnel(sk);
if (tunnel == NULL)
goto pass_up;