From: James Chapman <jchapman@katalix.com>
To: netdev@vger.kernel.org
Subject: [PATCH 05/12] l2tp: Add L2TPv3 protocol support
Date: Thu, 18 Mar 2010 10:21:54 +0000 [thread overview]
Message-ID: <20100318102154.14576.28661.stgit@bert.katalix.com> (raw)
In-Reply-To: <20100318102127.14576.98388.stgit@bert.katalix.com>
The L2TPv3 protocol changes the layout of the L2TP packet
header. Tunnel and session ids change from 16-bit to 32-bit values,
data sequence numbers change from 16-bit to 24-bit values and PPP-specific
fields are moved into protocol-specific subheaders.
Although this patch introduces L2TPv3 protocol support, there are no
userspace interfaces to create L2TPv3 sessions yet.
Signed-off-by: James Chapman <jchapman@katalix.com>
---
net/l2tp/Kconfig | 25 ++
net/l2tp/l2tp_core.c | 576 ++++++++++++++++++++++++++++++++++++++------------
net/l2tp/l2tp_core.h | 54 ++++-
net/l2tp/l2tp_ppp.c | 5
4 files changed, 510 insertions(+), 150 deletions(-)
diff --git a/net/l2tp/Kconfig b/net/l2tp/Kconfig
index ec88c5c..d60758d 100644
--- a/net/l2tp/Kconfig
+++ b/net/l2tp/Kconfig
@@ -19,6 +19,10 @@ menuconfig L2TP
connections. L2TP is also used as a VPN protocol, popular
with home workers to connect to their offices.
+ L2TPv3 allows other protocols as well as PPP to be carried
+ over L2TP tunnels. L2TPv3 is defined in RFC 3931
+ <http://www.ietf.org/rfc/rfc3931.txt>.
+
The kernel component handles only L2TP data packets: a
userland daemon handles L2TP the control protocol (tunnel
and session setup). One such daemon is OpenL2TP
@@ -26,3 +30,24 @@ menuconfig L2TP
If you don't need L2TP, say N. To compile all L2TP code as
modules, choose M here.
+
+config L2TP_V3
+ bool "L2TPv3 support (EXPERIMENTAL)"
+ depends on EXPERIMENTAL && L2TP
+ help
+ Layer Two Tunneling Protocol Version 3
+
+ From RFC 3931 <http://www.ietf.org/rfc/rfc3931.txt>.
+
+ The Layer Two Tunneling Protocol (L2TP) provides a dynamic
+ mechanism for tunneling Layer 2 (L2) "circuits" across a
+ packet-oriented data network (e.g., over IP). L2TP, as
+ originally defined in RFC 2661, is a standard method for
+ tunneling Point-to-Point Protocol (PPP) [RFC1661] sessions.
+ L2TP has since been adopted for tunneling a number of other
+ L2 protocols, including ATM, Frame Relay, HDLC and even raw
+ ethernet frames.
+
+ If you are connecting to L2TPv3 equipment, or you want to
+ tunnel raw ethernet frames using L2TP, say Y here. If
+ unsure, say N.
diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c
index f799c2c..8965b8a 100644
--- a/net/l2tp/l2tp_core.c
+++ b/net/l2tp/l2tp_core.c
@@ -66,6 +66,7 @@
#define L2TP_HDR_VER_MASK 0x000F
#define L2TP_HDR_VER_2 0x0002
+#define L2TP_HDR_VER_3 0x0003
/* L2TPv3 default L2-specific sublayer */
#define L2TP_SLFLAG_S 0x40000000
@@ -86,7 +87,7 @@
/* Private data stored for received packets in the skb.
*/
struct l2tp_skb_cb {
- u16 ns;
+ u32 ns;
u16 has_seq;
u16 length;
unsigned long expires;
@@ -102,6 +103,8 @@ static unsigned int l2tp_net_id;
struct l2tp_net {
struct list_head l2tp_tunnel_list;
rwlock_t l2tp_tunnel_list_lock;
+ struct hlist_head l2tp_session_hlist[L2TP_HASH_SIZE_2];
+ rwlock_t l2tp_session_hlist_lock;
};
static inline struct l2tp_net *l2tp_pernet(struct net *net)
@@ -111,6 +114,42 @@ static inline struct l2tp_net *l2tp_pernet(struct net *net)
return net_generic(net, l2tp_net_id);
}
+/* Session hash global list for L2TPv3.
+ * The session_id SHOULD be random according to RFC3931, but several
+ * L2TP implementations use incrementing session_ids. So we do a real
+ * hash on the session_id, rather than a simple bitmask.
+ */
+static inline struct hlist_head *
+l2tp_session_id_hash_2(struct l2tp_net *pn, u32 session_id)
+{
+ unsigned long hash_val = (unsigned long) session_id;
+
+ return &pn->l2tp_session_hlist[hash_long(hash_val, L2TP_HASH_BITS_2)];
+
+}
+
+/* Lookup a session by id in the global session list
+ */
+static struct l2tp_session *l2tp_session_find_2(struct net *net, u32 session_id)
+{
+ struct l2tp_net *pn = l2tp_pernet(net);
+ struct hlist_head *session_list =
+ l2tp_session_id_hash_2(pn, session_id);
+ struct l2tp_session *session;
+ struct hlist_node *walk;
+
+ read_lock_bh(&pn->l2tp_session_hlist_lock);
+ hlist_for_each_entry(session, walk, session_list, global_hlist) {
+ if (session->session_id == session_id) {
+ read_unlock_bh(&pn->l2tp_session_hlist_lock);
+ return session;
+ }
+ }
+ read_unlock_bh(&pn->l2tp_session_hlist_lock);
+
+ return NULL;
+}
+
/* Session hash list.
* The session_id SHOULD be random according to RFC2661, but several
* L2TP implementations (Cisco and Microsoft) use incrementing
@@ -126,13 +165,20 @@ l2tp_session_id_hash(struct l2tp_tunnel *tunnel, u32 session_id)
/* Lookup a session by id
*/
-struct l2tp_session *l2tp_session_find(struct l2tp_tunnel *tunnel, u32 session_id)
+struct l2tp_session *l2tp_session_find(struct net *net, struct l2tp_tunnel *tunnel, u32 session_id)
{
- struct hlist_head *session_list =
- l2tp_session_id_hash(tunnel, session_id);
+ struct hlist_head *session_list;
struct l2tp_session *session;
struct hlist_node *walk;
+ /* In L2TPv3, session_ids are unique over all tunnels and we
+ * sometimes need to look them up before we know the
+ * tunnel.
+ */
+ if (tunnel == NULL)
+ return l2tp_session_find_2(net, session_id);
+
+ session_list = l2tp_session_id_hash(tunnel, session_id);
read_lock_bh(&tunnel->hlist_lock);
hlist_for_each_entry(session, walk, session_list, hlist) {
if (session->session_id == session_id) {
@@ -223,7 +269,7 @@ static void l2tp_recv_queue_skb(struct l2tp_session *session, struct sk_buff *sk
{
struct sk_buff *skbp;
struct sk_buff *tmp;
- u16 ns = L2TP_SKB_CB(skb)->ns;
+ u32 ns = L2TP_SKB_CB(skb)->ns;
spin_lock_bh(&session->reorder_q.lock);
skb_queue_walk_safe(&session->reorder_q, skbp, tmp) {
@@ -264,6 +310,11 @@ static void l2tp_recv_dequeue_skb(struct l2tp_session *session, struct sk_buff *
if (L2TP_SKB_CB(skb)->has_seq) {
/* Bump our Nr */
session->nr++;
+ if (tunnel->version == L2TP_HDR_VER_2)
+ session->nr &= 0xffff;
+ else
+ session->nr &= 0xffffff;
+
PRINTK(session->debug, L2TP_MSG_SEQ, KERN_DEBUG,
"%s: updated nr to %hu\n", session->name, session->nr);
}
@@ -296,8 +347,8 @@ static void l2tp_recv_dequeue(struct l2tp_session *session)
session->stats.rx_seq_discards++;
session->stats.rx_errors++;
PRINTK(session->debug, L2TP_MSG_SEQ, KERN_DEBUG,
- "%s: oos pkt %hu len %d discarded (too old), "
- "waiting for %hu, reorder_q_len=%d\n",
+ "%s: oos pkt %u len %d discarded (too old), "
+ "waiting for %u, reorder_q_len=%d\n",
session->name, L2TP_SKB_CB(skb)->ns,
L2TP_SKB_CB(skb)->length, session->nr,
skb_queue_len(&session->reorder_q));
@@ -311,8 +362,8 @@ static void l2tp_recv_dequeue(struct l2tp_session *session)
if (L2TP_SKB_CB(skb)->has_seq) {
if (L2TP_SKB_CB(skb)->ns != session->nr) {
PRINTK(session->debug, L2TP_MSG_SEQ, KERN_DEBUG,
- "%s: holding oos pkt %hu len %d, "
- "waiting for %hu, reorder_q_len=%d\n",
+ "%s: holding oos pkt %u len %d, "
+ "waiting for %u, reorder_q_len=%d\n",
session->name, L2TP_SKB_CB(skb)->ns,
L2TP_SKB_CB(skb)->length, session->nr,
skb_queue_len(&session->reorder_q));
@@ -357,100 +408,73 @@ static inline int l2tp_verify_udp_checksum(struct sock *sk,
return __skb_checksum_complete(skb);
}
-/* Internal UDP 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.
+/* Do receive processing of L2TP data frames. We handle both L2TPv2
+ * and L2TPv3 data frames here.
+ *
+ * L2TPv2 Data Message Header
+ *
+ * 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |T|L|x|x|S|x|O|P|x|x|x|x| Ver | Length (opt) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Tunnel ID | Session ID |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Ns (opt) | Nr (opt) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Offset Size (opt) | Offset pad... (opt)
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * Data frames are marked by T=0. All other fields are the same as
+ * those in L2TP control frames.
+ *
+ * L2TPv3 Data Message Header
+ *
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | L2TP Session Header |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | L2-Specific Sublayer |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Tunnel Payload ...
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * L2TPv3 Session Header Over IP
+ *
+ * 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Session ID |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Cookie (optional, maximum 64 bits)...
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * L2TPv3 L2-Specific Sublayer Format
+ *
+ * 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |x|S|x|x|x|x|x|x| Sequence Number |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * Cookie value, sublayer format and offset (pad) are negotiated with
+ * the peer when the session is set up. Unlike L2TPv2, we do not need
+ * to parse the packet header to determine if optional fields are
+ * present.
+ *
+ * Caller must already have parsed the frame and determined that it is
+ * a data (not control) frame before coming here. Fields up to the
+ * session-id have already been parsed and ptr points to the data
+ * after the session-id.
*/
-int l2tp_udp_recv_core(struct l2tp_tunnel *tunnel, struct sk_buff *skb,
- int (*payload_hook)(struct sk_buff *skb))
+void l2tp_recv_common(struct l2tp_session *session, struct sk_buff *skb,
+ unsigned char *ptr, unsigned char *optr, u16 hdrflags,
+ int length, int (*payload_hook)(struct sk_buff *skb))
{
- struct l2tp_session *session = NULL;
- unsigned char *ptr, *optr;
- u16 hdrflags;
- u32 tunnel_id, session_id;
- int length;
+ struct l2tp_tunnel *tunnel = session->tunnel;
int offset;
- u16 version;
- u16 ns, nr;
-
- if (tunnel->sock && l2tp_verify_udp_checksum(tunnel->sock, skb))
- goto discard_bad_csum;
-
- /* UDP always verifies the packet length. */
- __skb_pull(skb, sizeof(struct udphdr));
-
- /* Short packet? */
- if (!pskb_may_pull(skb, L2TP_HDR_SIZE_SEQ)) {
- PRINTK(tunnel->debug, L2TP_MSG_DATA, KERN_INFO,
- "%s: recv short packet (len=%d)\n", tunnel->name, skb->len);
- goto error;
- }
-
- /* Point to L2TP header */
- optr = ptr = skb->data;
-
- /* Trace packet contents, if enabled */
- if (tunnel->debug & L2TP_MSG_DATA) {
- length = min(32u, skb->len);
- if (!pskb_may_pull(skb, length))
- goto error;
-
- printk(KERN_DEBUG "%s: recv: ", tunnel->name);
-
- offset = 0;
- do {
- printk(" %02X", ptr[offset]);
- } while (++offset < length);
-
- printk("\n");
- }
-
- /* Get L2TP header flags */
- hdrflags = ntohs(*(__be16 *)ptr);
-
- /* Check protocol version */
- version = hdrflags & L2TP_HDR_VER_MASK;
- if (version != tunnel->version) {
- PRINTK(tunnel->debug, L2TP_MSG_DATA, KERN_INFO,
- "%s: recv protocol version mismatch: got %d expected %d\n",
- tunnel->name, version, tunnel->version);
- goto error;
- }
-
- /* Get length of L2TP packet */
- length = skb->len;
-
- /* If type is control packet, it is handled by userspace. */
- if (hdrflags & L2TP_HDRFLAG_T) {
- PRINTK(tunnel->debug, L2TP_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 = l2tp_session_find(tunnel, session_id);
- if (!session) {
- /* Not found? Pass to userspace to deal with */
- PRINTK(tunnel->debug, L2TP_MSG_DATA, KERN_INFO,
- "%s: no session found (%hu/%hu). Passing up.\n",
- tunnel->name, tunnel_id, session_id);
- goto error;
- }
+ u32 ns, nr;
/* The ref count is increased since we now hold a pointer to
* the session. Take care to decrement the refcnt when exiting
@@ -460,6 +484,18 @@ int l2tp_udp_recv_core(struct l2tp_tunnel *tunnel, struct sk_buff *skb,
if (session->ref)
(*session->ref)(session);
+ /* Parse and check optional cookie */
+ if (session->peer_cookie_len > 0) {
+ if (memcmp(ptr, &session->peer_cookie[0], session->peer_cookie_len)) {
+ PRINTK(tunnel->debug, L2TP_MSG_DATA, KERN_INFO,
+ "%s: cookie mismatch (%u/%u). Discarding.\n",
+ tunnel->name, tunnel->tunnel_id, session->session_id);
+ session->stats.rx_cookie_discards++;
+ goto discard;
+ }
+ ptr += session->peer_cookie_len;
+ }
+
/* Handle the optional sequence numbers. Sequence numbers are
* in different places for L2TPv2 and L2TPv3.
*
@@ -469,21 +505,40 @@ int l2tp_udp_recv_core(struct l2tp_tunnel *tunnel, struct sk_buff *skb,
*/
ns = nr = 0;
L2TP_SKB_CB(skb)->has_seq = 0;
- if (hdrflags & L2TP_HDRFLAG_S) {
- ns = (u16) ntohs(*(__be16 *) ptr);
- ptr += 2;
- nr = ntohs(*(__be16 *) ptr);
- ptr += 2;
+ if (tunnel->version == L2TP_HDR_VER_2) {
+ if (hdrflags & L2TP_HDRFLAG_S) {
+ ns = ntohs(*(__be16 *) ptr);
+ ptr += 2;
+ nr = ntohs(*(__be16 *) ptr);
+ ptr += 2;
- /* Store L2TP info in the skb */
- L2TP_SKB_CB(skb)->ns = ns;
- L2TP_SKB_CB(skb)->has_seq = 1;
+ /* Store L2TP info in the skb */
+ L2TP_SKB_CB(skb)->ns = ns;
+ L2TP_SKB_CB(skb)->has_seq = 1;
- PRINTK(session->debug, L2TP_MSG_SEQ, KERN_DEBUG,
- "%s: recv data ns=%hu, nr=%hu, session nr=%hu\n",
- session->name, ns, nr, session->nr);
+ PRINTK(session->debug, L2TP_MSG_SEQ, KERN_DEBUG,
+ "%s: recv data ns=%u, nr=%u, session nr=%u\n",
+ session->name, ns, nr, session->nr);
+ }
+ } else if (session->l2specific_type == L2TP_L2SPECTYPE_DEFAULT) {
+ u32 l2h = ntohl(*(__be32 *) ptr);
+
+ if (l2h & 0x40000000) {
+ ns = l2h & 0x00ffffff;
+
+ /* Store L2TP info in the skb */
+ L2TP_SKB_CB(skb)->ns = ns;
+ L2TP_SKB_CB(skb)->has_seq = 1;
+
+ PRINTK(session->debug, L2TP_MSG_SEQ, KERN_DEBUG,
+ "%s: recv data ns=%u, session nr=%u\n",
+ session->name, ns, session->nr);
+ }
}
+ /* Advance past L2-specific header, if present */
+ ptr += session->l2specific_len;
+
if (L2TP_SKB_CB(skb)->has_seq) {
/* Received a packet with sequence numbers. If we're the LNS,
* check if we sre sending sequence numbers and if not,
@@ -494,6 +549,7 @@ int l2tp_udp_recv_core(struct l2tp_tunnel *tunnel, struct sk_buff *skb,
"%s: requested to enable seq numbers by LNS\n",
session->name);
session->send_seq = -1;
+ l2tp_session_set_header_len(session, tunnel->version);
}
} else {
/* No sequence numbers.
@@ -517,6 +573,7 @@ int l2tp_udp_recv_core(struct l2tp_tunnel *tunnel, struct sk_buff *skb,
"%s: requested to disable seq numbers by LNS\n",
session->name);
session->send_seq = 0;
+ l2tp_session_set_header_len(session, tunnel->version);
} else if (session->send_seq) {
PRINTK(session->debug, L2TP_MSG_SEQ, KERN_WARNING,
"%s: recv data has no seq numbers when required. "
@@ -526,11 +583,19 @@ int l2tp_udp_recv_core(struct l2tp_tunnel *tunnel, struct sk_buff *skb,
}
}
- /* If offset bit set, skip it. */
- if (hdrflags & L2TP_HDRFLAG_O) {
- offset = ntohs(*(__be16 *)ptr);
- ptr += 2 + offset;
- }
+ /* Session data offset is handled differently for L2TPv2 and
+ * L2TPv3. For L2TPv2, there is an optional 16-bit value in
+ * the header. For L2TPv3, the offset is negotiated using AVPs
+ * in the session setup control protocol.
+ */
+ if (tunnel->version == L2TP_HDR_VER_2) {
+ /* If offset bit set, skip it. */
+ if (hdrflags & L2TP_HDRFLAG_O) {
+ offset = ntohs(*(__be16 *)ptr);
+ ptr += 2 + offset;
+ }
+ } else
+ ptr += session->offset;
offset = ptr - optr;
if (!pskb_may_pull(skb, offset))
@@ -569,8 +634,8 @@ int l2tp_udp_recv_core(struct l2tp_tunnel *tunnel, struct sk_buff *skb,
if (L2TP_SKB_CB(skb)->ns != session->nr) {
session->stats.rx_seq_discards++;
PRINTK(session->debug, L2TP_MSG_SEQ, KERN_DEBUG,
- "%s: oos pkt %hu len %d discarded, "
- "waiting for %hu, reorder_q_len=%d\n",
+ "%s: oos pkt %u len %d discarded, "
+ "waiting for %u, reorder_q_len=%d\n",
session->name, L2TP_SKB_CB(skb)->ns,
L2TP_SKB_CB(skb)->length, session->nr,
skb_queue_len(&session->reorder_q));
@@ -591,7 +656,7 @@ int l2tp_udp_recv_core(struct l2tp_tunnel *tunnel, struct sk_buff *skb,
l2tp_session_dec_refcount(session);
- return 0;
+ return;
discard:
session->stats.rx_errors++;
@@ -601,6 +666,111 @@ discard:
(*session->deref)(session);
l2tp_session_dec_refcount(session);
+}
+EXPORT_SYMBOL(l2tp_recv_common);
+
+/* Internal UDP 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.
+ */
+int l2tp_udp_recv_core(struct l2tp_tunnel *tunnel, struct sk_buff *skb,
+ int (*payload_hook)(struct sk_buff *skb))
+{
+ struct l2tp_session *session = NULL;
+ unsigned char *ptr, *optr;
+ u16 hdrflags;
+ u32 tunnel_id, session_id;
+ int offset;
+ u16 version;
+ int length;
+
+ if (tunnel->sock && l2tp_verify_udp_checksum(tunnel->sock, skb))
+ goto discard_bad_csum;
+
+ /* UDP always verifies the packet length. */
+ __skb_pull(skb, sizeof(struct udphdr));
+
+ /* Short packet? */
+ if (!pskb_may_pull(skb, L2TP_HDR_SIZE_SEQ)) {
+ PRINTK(tunnel->debug, L2TP_MSG_DATA, KERN_INFO,
+ "%s: recv short packet (len=%d)\n", tunnel->name, skb->len);
+ goto error;
+ }
+
+ /* Point to L2TP header */
+ optr = ptr = skb->data;
+
+ /* Trace packet contents, if enabled */
+ if (tunnel->debug & L2TP_MSG_DATA) {
+ length = min(32u, skb->len);
+ if (!pskb_may_pull(skb, length))
+ goto error;
+
+ printk(KERN_DEBUG "%s: recv: ", tunnel->name);
+
+ offset = 0;
+ do {
+ printk(" %02X", ptr[offset]);
+ } while (++offset < length);
+
+ printk("\n");
+ }
+
+ /* Get L2TP header flags */
+ hdrflags = ntohs(*(__be16 *) ptr);
+
+ /* Check protocol version */
+ version = hdrflags & L2TP_HDR_VER_MASK;
+ if (version != tunnel->version) {
+ PRINTK(tunnel->debug, L2TP_MSG_DATA, KERN_INFO,
+ "%s: recv protocol version mismatch: got %d expected %d\n",
+ tunnel->name, version, tunnel->version);
+ goto error;
+ }
+
+ /* Get length of L2TP packet */
+ length = skb->len;
+
+ /* If type is control packet, it is handled by userspace. */
+ if (hdrflags & L2TP_HDRFLAG_T) {
+ PRINTK(tunnel->debug, L2TP_MSG_DATA, KERN_DEBUG,
+ "%s: recv control packet, len=%d\n", tunnel->name, length);
+ goto error;
+ }
+
+ /* Skip flags */
+ ptr += 2;
+
+ if (tunnel->version == L2TP_HDR_VER_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;
+ } else {
+ ptr += 2; /* skip reserved bits */
+ tunnel_id = tunnel->tunnel_id;
+ session_id = ntohl(*(__be32 *) ptr);
+ ptr += 4;
+ }
+
+ /* Find the session context */
+ session = l2tp_session_find(tunnel->l2tp_net, tunnel, session_id);
+ if (!session) {
+ /* Not found? Pass to userspace to deal with */
+ PRINTK(tunnel->debug, L2TP_MSG_DATA, KERN_INFO,
+ "%s: no session found (%u/%u). Passing up.\n",
+ tunnel->name, tunnel_id, session_id);
+ goto error;
+ }
+
+ l2tp_recv_common(session, skb, ptr, optr, hdrflags, length, payload_hook);
return 0;
@@ -656,11 +826,11 @@ EXPORT_SYMBOL_GPL(l2tp_udp_encap_recv);
/* Build an L2TP header for the session into the buffer provided.
*/
-static void l2tp_build_l2tpv2_header(struct l2tp_tunnel *tunnel,
- struct l2tp_session *session,
- void *buf)
+static int l2tp_build_l2tpv2_header(struct l2tp_session *session, void *buf)
{
+ struct l2tp_tunnel *tunnel = session->tunnel;
__be16 *bufp = buf;
+ __be16 *optr = buf;
u16 flags = L2TP_HDR_VER_2;
u32 tunnel_id = tunnel->peer_tunnel_id;
u32 session_id = session->peer_session_id;
@@ -676,19 +846,51 @@ static void l2tp_build_l2tpv2_header(struct l2tp_tunnel *tunnel,
*bufp++ = htons(session->ns);
*bufp++ = 0;
session->ns++;
+ session->ns &= 0xffff;
PRINTK(session->debug, L2TP_MSG_SEQ, KERN_DEBUG,
- "%s: updated ns to %hu\n", session->name, session->ns);
+ "%s: updated ns to %u\n", session->name, session->ns);
}
+
+ return bufp - optr;
}
-void l2tp_build_l2tp_header(struct l2tp_session *session, void *buf)
+static int l2tp_build_l2tpv3_header(struct l2tp_session *session, void *buf)
{
- struct l2tp_tunnel *tunnel = session->tunnel;
+ char *bufp = buf;
+ char *optr = bufp;
+ u16 flags = L2TP_HDR_VER_3;
- BUG_ON(tunnel->version != L2TP_HDR_VER_2);
- l2tp_build_l2tpv2_header(tunnel, session, buf);
+ /* Setup L2TP header. */
+ *((__be16 *) bufp) = htons(flags);
+ bufp += 2;
+ *((__be16 *) bufp) = 0;
+ bufp += 2;
+ *((__be32 *) bufp) = htonl(session->peer_session_id);
+ bufp += 4;
+ if (session->cookie_len) {
+ memcpy(bufp, &session->cookie[0], session->cookie_len);
+ bufp += session->cookie_len;
+ }
+ if (session->l2specific_len) {
+ if (session->l2specific_type == L2TP_L2SPECTYPE_DEFAULT) {
+ u32 l2h = 0;
+ if (session->send_seq) {
+ l2h = 0x40000000 | session->ns;
+ session->ns++;
+ session->ns &= 0xffffff;
+ PRINTK(session->debug, L2TP_MSG_SEQ, KERN_DEBUG,
+ "%s: updated ns to %u\n", session->name, session->ns);
+ }
+
+ *((__be32 *) bufp) = htonl(l2h);
+ }
+ bufp += session->l2specific_len;
+ }
+ if (session->offset)
+ bufp += session->offset;
+
+ return bufp - optr;
}
-EXPORT_SYMBOL_GPL(l2tp_build_l2tp_header);
int l2tp_xmit_core(struct l2tp_session *session, struct sk_buff *skb, size_t data_len)
{
@@ -699,7 +901,7 @@ int l2tp_xmit_core(struct l2tp_session *session, struct sk_buff *skb, size_t dat
/* Debug */
if (session->send_seq)
PRINTK(session->debug, L2TP_MSG_DATA, KERN_DEBUG,
- "%s: send %Zd bytes, ns=%hu\n", session->name,
+ "%s: send %Zd bytes, ns=%u\n", session->name,
data_len, session->ns - 1);
else
PRINTK(session->debug, L2TP_MSG_DATA, KERN_DEBUG,
@@ -785,7 +987,7 @@ int l2tp_xmit_skb(struct l2tp_session *session, struct sk_buff *skb, int hdr_len
skb->truesize += new_headroom - old_headroom;
/* Setup L2TP header */
- l2tp_build_l2tp_header(session, __skb_push(skb, hdr_len));
+ session->build_header(session, __skb_push(skb, hdr_len));
udp_len = sizeof(struct udphdr) + hdr_len + data_len;
/* Setup UDP header */
@@ -796,7 +998,6 @@ int l2tp_xmit_skb(struct l2tp_session *session, struct sk_buff *skb, int hdr_len
uh->source = inet->inet_sport;
uh->dest = inet->inet_dport;
uh->len = htons(udp_len);
-
uh->check = 0;
memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
@@ -916,6 +1117,14 @@ again:
write_unlock_bh(&tunnel->hlist_lock);
+ if (tunnel->version != L2TP_HDR_VER_2) {
+ struct l2tp_net *pn = l2tp_pernet(tunnel->l2tp_net);
+
+ write_lock_bh(&pn->l2tp_session_hlist_lock);
+ hlist_del_init(&session->global_hlist);
+ write_unlock_bh(&pn->l2tp_session_hlist_lock);
+ }
+
if (session->session_close != NULL)
(*session->session_close)(session);
@@ -1002,9 +1211,6 @@ int l2tp_tunnel_create(struct net *net, int fd, int version, u32 tunnel_id, u32
goto err;
}
- if (version != L2TP_HDR_VER_2)
- goto err;
-
tunnel = kzalloc(sizeof(struct l2tp_tunnel), GFP_KERNEL);
if (tunnel == NULL) {
err = -ENOMEM;
@@ -1082,6 +1288,15 @@ void l2tp_session_free(struct l2tp_session *session)
hlist_del_init(&session->hlist);
write_unlock_bh(&tunnel->hlist_lock);
+ /* Unlink from the global hash if not L2TPv2 */
+ if (tunnel->version != L2TP_HDR_VER_2) {
+ struct l2tp_net *pn = l2tp_pernet(tunnel->l2tp_net);
+
+ write_lock_bh(&pn->l2tp_session_hlist_lock);
+ hlist_del_init(&session->global_hlist);
+ write_unlock_bh(&pn->l2tp_session_hlist_lock);
+ }
+
if (session->session_id != 0)
atomic_dec(&l2tp_session_count);
@@ -1100,6 +1315,22 @@ void l2tp_session_free(struct l2tp_session *session)
}
EXPORT_SYMBOL_GPL(l2tp_session_free);
+/* We come here whenever a session's send_seq, cookie_len or
+ * l2specific_len parameters are set.
+ */
+void l2tp_session_set_header_len(struct l2tp_session *session, int version)
+{
+ if (version == L2TP_HDR_VER_2) {
+ session->hdr_len = 6;
+ if (session->send_seq)
+ session->hdr_len += 4;
+ } else {
+ session->hdr_len = 8 + session->cookie_len + session->l2specific_len + session->offset;
+ }
+
+}
+EXPORT_SYMBOL_GPL(l2tp_session_set_header_len);
+
struct l2tp_session *l2tp_session_create(int priv_size, struct l2tp_tunnel *tunnel, u32 session_id, u32 peer_session_id, struct l2tp_session_cfg *cfg)
{
struct l2tp_session *session;
@@ -1111,6 +1342,7 @@ struct l2tp_session *l2tp_session_create(int priv_size, struct l2tp_tunnel *tunn
session->session_id = session_id;
session->peer_session_id = peer_session_id;
+ session->nr = 1;
sprintf(&session->name[0], "sess %u/%u",
tunnel->tunnel_id, session->session_id);
@@ -1118,20 +1350,36 @@ struct l2tp_session *l2tp_session_create(int priv_size, struct l2tp_tunnel *tunn
skb_queue_head_init(&session->reorder_q);
INIT_HLIST_NODE(&session->hlist);
+ INIT_HLIST_NODE(&session->global_hlist);
/* Inherit debug options from tunnel */
session->debug = tunnel->debug;
if (cfg) {
+ session->pwtype = cfg->pw_type;
session->debug = cfg->debug;
- session->hdr_len = cfg->hdr_len;
session->mtu = cfg->mtu;
session->mru = cfg->mru;
session->send_seq = cfg->send_seq;
session->recv_seq = cfg->recv_seq;
session->lns_mode = cfg->lns_mode;
+ session->reorder_timeout = cfg->reorder_timeout;
+ session->offset = cfg->offset;
+ session->l2specific_type = cfg->l2specific_type;
+ session->l2specific_len = cfg->l2specific_len;
+ session->cookie_len = cfg->cookie_len;
+ memcpy(&session->cookie[0], &cfg->cookie[0], cfg->cookie_len);
+ session->peer_cookie_len = cfg->peer_cookie_len;
+ memcpy(&session->peer_cookie[0], &cfg->peer_cookie[0], cfg->peer_cookie_len);
}
+ if (tunnel->version == L2TP_HDR_VER_2)
+ session->build_header = l2tp_build_l2tpv2_header;
+ else
+ session->build_header = l2tp_build_l2tpv3_header;
+
+ l2tp_session_set_header_len(session, tunnel->version);
+
/* Bump the reference count. The session context is deleted
* only when this drops to zero.
*/
@@ -1147,6 +1395,16 @@ struct l2tp_session *l2tp_session_create(int priv_size, struct l2tp_tunnel *tunn
l2tp_session_id_hash(tunnel, session_id));
write_unlock_bh(&tunnel->hlist_lock);
+ /* And to the global session list if L2TPv3 */
+ if (tunnel->version != L2TP_HDR_VER_2) {
+ struct l2tp_net *pn = l2tp_pernet(tunnel->l2tp_net);
+
+ write_lock_bh(&pn->l2tp_session_hlist_lock);
+ hlist_add_head(&session->global_hlist,
+ l2tp_session_id_hash_2(pn, session_id));
+ write_unlock_bh(&pn->l2tp_session_hlist_lock);
+ }
+
/* Ignore management session in session count value */
if (session->session_id != 0)
atomic_inc(&l2tp_session_count);
@@ -1290,6 +1548,7 @@ static void l2tp_seq_tunnel_show(struct seq_file *m, void *v)
seq_printf(m, " source port %hu, dest port %hu\n",
ntohs(inet->inet_sport), ntohs(inet->inet_dport));
}
+ seq_printf(m, " L2TPv%d\n", tunnel->version);
seq_printf(m, " %d sessions, refcnt %d/%d\n", session_count,
tunnel->sock ? atomic_read(&tunnel->sock->sk_refcnt) : 0,
atomic_read(&tunnel->ref_count));
@@ -1311,17 +1570,46 @@ static void l2tp_seq_session_show(struct seq_file *m, void *v)
{
struct l2tp_session *session = v;
- seq_printf(m, " SESSION %u, peer %u\n", session->session_id, session->peer_session_id);
+ seq_printf(m, " SESSION %u, peer %u, %s\n", session->session_id,
+ session->peer_session_id,
+ session->pwtype == L2TP_PWTYPE_ETH ? "ETH" :
+ session->pwtype == L2TP_PWTYPE_PPP ? "PPP" :
+ "");
if (session->send_seq || session->recv_seq)
seq_printf(m, " nr %hu, ns %hu\n", session->nr, session->ns);
seq_printf(m, " refcnt %d\n", atomic_read(&session->ref_count));
- seq_printf(m, " config %d/%d/%c/%c/%s %08x %u\n",
+ seq_printf(m, " config %d/%d/%c/%c/%s/%s %08x %u\n",
session->mtu, session->mru,
session->recv_seq ? 'R' : '-',
session->send_seq ? 'S' : '-',
+ session->data_seq == 1 ? "IPSEQ" :
+ session->data_seq == 2 ? "DATASEQ" : "-",
session->lns_mode ? "LNS" : "LAC",
session->debug,
jiffies_to_msecs(session->reorder_timeout));
+ seq_printf(m, " offset %hu l2specific %hu/%hu\n",
+ session->offset, session->l2specific_type, session->l2specific_len);
+ if (session->cookie_len) {
+ seq_printf(m, " cookie %02x%02x%02x%02x",
+ session->cookie[0], session->cookie[1],
+ session->cookie[2], session->cookie[3]);
+ if (session->cookie_len == 8)
+ seq_printf(m, "%02x%02x%02x%02x",
+ session->cookie[4], session->cookie[5],
+ session->cookie[6], session->cookie[7]);
+ seq_printf(m, "\n");
+ }
+ if (session->peer_cookie_len) {
+ seq_printf(m, " peer cookie %02x%02x%02x%02x",
+ session->peer_cookie[0], session->peer_cookie[1],
+ session->peer_cookie[2], session->peer_cookie[3]);
+ if (session->peer_cookie_len == 8)
+ seq_printf(m, "%02x%02x%02x%02x",
+ session->peer_cookie[4], session->peer_cookie[5],
+ session->peer_cookie[6], session->peer_cookie[7]);
+ seq_printf(m, "\n");
+ }
+
seq_printf(m, " %hu/%hu tx %llu/%llu/%llu rx %llu/%llu/%llu\n",
session->nr, session->ns,
(unsigned long long)session->stats.tx_packets,
@@ -1343,11 +1631,15 @@ static int l2tp_seq_show(struct seq_file *m, void *v)
if (v == SEQ_START_TOKEN) {
seq_puts(m, "L2TP driver info, " L2TP_DRV_VERSION "\n");
seq_puts(m, "TUNNEL ID, peer ID from IP to IP\n");
+ seq_puts(m, " L2TPv2/L2TPv3\n");
seq_puts(m, " sessions session-count, refcnt refcnt/sk->refcnt\n");
seq_puts(m, " debug tx-pkts/bytes/errs rx-pkts/bytes/errs\n");
- seq_puts(m, " SESSION ID, peer ID\n");
+ seq_puts(m, " SESSION ID, peer ID, PWTYPE\n");
seq_puts(m, " refcnt cnt\n");
- seq_puts(m, " mtu/mru/rcvseq/sendseq/lns debug reorderto\n");
+ seq_puts(m, " offset OFFSET l2specific TYPE/LEN\n");
+ seq_puts(m, " [ cookie ]\n");
+ seq_puts(m, " [ peer cookie ]\n");
+ seq_puts(m, " config mtu/mru/rcvseq/sendseq/dataseq/lns debug reorderto\n");
seq_puts(m, " nr/ns tx-pkts/bytes/errs rx-pkts/bytes/errs\n");
seq_printf(m, "tunnels %d sessions %d\n", atomic_read(&l2tp_tunnel_count), atomic_read(&l2tp_session_count));
@@ -1397,6 +1689,7 @@ static __net_init int l2tp_init_net(struct net *net)
struct l2tp_net *pn;
struct proc_dir_entry *pde;
int err;
+ int hash;
pn = kzalloc(sizeof(*pn), GFP_KERNEL);
if (!pn)
@@ -1405,6 +1698,11 @@ static __net_init int l2tp_init_net(struct net *net)
INIT_LIST_HEAD(&pn->l2tp_tunnel_list);
rwlock_init(&pn->l2tp_tunnel_list_lock);
+ for (hash = 0; hash < L2TP_HASH_SIZE_2; hash++)
+ INIT_HLIST_HEAD(&pn->l2tp_session_hlist[hash]);
+
+ rwlock_init(&pn->l2tp_session_hlist_lock);
+
err = net_assign_generic(net, l2tp_net_id, pn);
if (err)
goto out;
diff --git a/net/l2tp/l2tp_core.h b/net/l2tp/l2tp_core.h
index 80ce1ce..87a06b2 100644
--- a/net/l2tp/l2tp_core.h
+++ b/net/l2tp/l2tp_core.h
@@ -15,9 +15,14 @@
#define L2TP_TUNNEL_MAGIC 0x42114DDA
#define L2TP_SESSION_MAGIC 0x0C04EB7D
+/* Per tunnel, session hash table size */
#define L2TP_HASH_BITS 4
#define L2TP_HASH_SIZE (1 << L2TP_HASH_BITS)
+/* System-wide, session hash table size */
+#define L2TP_HASH_BITS_2 8
+#define L2TP_HASH_SIZE_2 (1 << L2TP_HASH_BITS_2)
+
/* Debug message categories for the DEBUG socket option */
enum {
L2TP_MSG_DEBUG = (1 << 0), /* verbose debug (if
@@ -28,6 +33,21 @@ enum {
L2TP_MSG_DATA = (1 << 3), /* data packets */
};
+enum l2tp_pwtype {
+ L2TP_PWTYPE_NONE = 0x0000,
+ L2TP_PWTYPE_ETH_VLAN = 0x0004,
+ L2TP_PWTYPE_ETH = 0x0005,
+ L2TP_PWTYPE_PPP = 0x0007,
+ L2TP_PWTYPE_PPP_AC = 0x0008,
+ L2TP_PWTYPE_IP = 0x000b,
+ __L2TP_PWTYPE_MAX
+};
+
+enum l2tp_l2spec_type {
+ L2TP_L2SPECTYPE_NONE,
+ L2TP_L2SPECTYPE_DEFAULT,
+};
+
struct sk_buff;
struct l2tp_stats {
@@ -39,6 +59,7 @@ struct l2tp_stats {
u64 rx_seq_discards;
u64 rx_oos_packets;
u64 rx_errors;
+ u64 rx_cookie_discards;
};
struct l2tp_tunnel;
@@ -47,6 +68,7 @@ struct l2tp_tunnel;
* packets and transmit outgoing ones.
*/
struct l2tp_session_cfg {
+ enum l2tp_pwtype pw_type;
unsigned data_seq:2; /* data sequencing level
* 0 => none, 1 => IP only,
* 2 => all
@@ -60,12 +82,17 @@ struct l2tp_session_cfg {
* control of LNS. */
int debug; /* bitmask of debug message
* categories */
- int offset; /* offset to payload */
+ u16 offset; /* offset to payload */
+ u16 l2specific_len; /* Layer 2 specific length */
+ u16 l2specific_type; /* Layer 2 specific type */
+ u8 cookie[8]; /* optional cookie */
+ int cookie_len; /* 0, 4 or 8 bytes */
+ u8 peer_cookie[8]; /* peer's cookie */
+ int peer_cookie_len; /* 0, 4 or 8 bytes */
int reorder_timeout; /* configured reorder timeout
* (in jiffies) */
int mtu;
int mru;
- int hdr_len;
};
struct l2tp_session {
@@ -76,8 +103,17 @@ struct l2tp_session {
* context */
u32 session_id;
u32 peer_session_id;
- u16 nr; /* session NR state (receive) */
- u16 ns; /* session NR state (send) */
+ u8 cookie[8];
+ int cookie_len;
+ u8 peer_cookie[8];
+ int peer_cookie_len;
+ u16 offset; /* offset from end of L2TP header
+ to beginning of data */
+ u16 l2specific_len;
+ u16 l2specific_type;
+ u16 hdr_len;
+ u32 nr; /* session NR state (receive) */
+ u32 ns; /* session NR state (send) */
struct sk_buff_head reorder_q; /* receive reorder queue */
struct hlist_node hlist; /* Hash list node */
atomic_t ref_count;
@@ -100,9 +136,11 @@ struct l2tp_session {
* (in jiffies) */
int mtu;
int mru;
- int hdr_len;
+ enum l2tp_pwtype pwtype;
struct l2tp_stats stats;
+ struct hlist_node global_hlist; /* Global hash list node */
+ int (*build_header)(struct l2tp_session *session, void *buf);
void (*recv_skb)(struct l2tp_session *session, struct sk_buff *skb, int data_len);
void (*session_close)(struct l2tp_session *session);
void (*ref)(struct l2tp_session *session);
@@ -134,7 +172,6 @@ struct l2tp_tunnel {
char name[20]; /* for logging */
int debug; /* bitmask of debug message
* categories */
- int hdr_len;
struct l2tp_stats stats;
struct list_head list; /* Keep a list of all tunnels */
@@ -182,7 +219,7 @@ out:
return tunnel;
}
-extern struct l2tp_session *l2tp_session_find(struct l2tp_tunnel *tunnel, u32 session_id);
+extern struct l2tp_session *l2tp_session_find(struct net *net, struct l2tp_tunnel *tunnel, u32 session_id);
extern struct l2tp_session *l2tp_session_find_nth(struct l2tp_tunnel *tunnel, int nth, int *skipped);
extern struct l2tp_tunnel *l2tp_tunnel_find(struct net *net, u32 tunnel_id);
extern struct l2tp_session *l2tp_session_find_nth(struct l2tp_tunnel *tunnel, int nth, int *skipped);
@@ -191,14 +228,15 @@ extern int l2tp_tunnel_create(struct net *net, int fd, int version, u32 tunnel_i
extern struct l2tp_session *l2tp_session_create(int priv_size, struct l2tp_tunnel *tunnel, u32 session_id, u32 peer_session_id, struct l2tp_session_cfg *cfg);
extern void l2tp_tunnel_free(struct l2tp_tunnel *tunnel);
extern void l2tp_session_free(struct l2tp_session *session);
+extern void l2tp_recv_common(struct l2tp_session *session, struct sk_buff *skb, unsigned char *ptr, unsigned char *optr, u16 hdrflags, int length, int (*payload_hook)(struct sk_buff *skb));
extern int l2tp_udp_recv_core(struct l2tp_tunnel *tunnel, struct sk_buff *skb, int (*payload_hook)(struct sk_buff *skb));
extern int l2tp_udp_encap_recv(struct sock *sk, struct sk_buff *skb);
-extern void l2tp_build_l2tp_header(struct l2tp_session *session, void *buf);
extern int l2tp_xmit_core(struct l2tp_session *session, struct sk_buff *skb, size_t data_len);
extern int l2tp_xmit_skb(struct l2tp_session *session, struct sk_buff *skb, int hdr_len);
extern void l2tp_tunnel_destruct(struct sock *sk);
extern void l2tp_tunnel_closeall(struct l2tp_tunnel *tunnel);
+extern void l2tp_session_set_header_len(struct l2tp_session *session, int version);
/* Tunnel reference counts. Incremented per session that is added to
* the tunnel.
diff --git a/net/l2tp/l2tp_ppp.c b/net/l2tp/l2tp_ppp.c
index 8f78c27..dc27543 100644
--- a/net/l2tp/l2tp_ppp.c
+++ b/net/l2tp/l2tp_ppp.c
@@ -684,7 +684,7 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr,
/* Check that this session doesn't already exist */
error = -EEXIST;
- session = l2tp_session_find(tunnel, sp->pppol2tp.s_session);
+ session = l2tp_session_find(sock_net(sk), tunnel, sp->pppol2tp.s_session);
if (session != NULL)
goto end;
@@ -692,7 +692,6 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr,
* headers.
*/
cfg.mtu = cfg.mru = 1500 - PPPOL2TP_HEADER_OVERHEAD;
- cfg.hdr_len = PPPOL2TP_L2TP_HDR_SIZE_NOSEQ;
cfg.debug = tunnel->debug;
/* Allocate and initialize a new session context. */
@@ -1016,7 +1015,7 @@ static int pppol2tp_tunnel_ioctl(struct l2tp_tunnel *tunnel,
if (stats.session_id != 0) {
/* resend to session ioctl handler */
struct l2tp_session *session =
- l2tp_session_find(tunnel, stats.session_id);
+ l2tp_session_find(sock_net(sk), tunnel, stats.session_id);
if (session != NULL)
err = pppol2tp_session_ioctl(session, cmd, arg);
else
next prev parent reply other threads:[~2010-03-18 10:22 UTC|newest]
Thread overview: 17+ messages / expand[flat|nested] mbox.gz Atom feed top
2010-03-18 10:21 [PATCH 00/12] l2tp: Introduce L2TPv3 support James Chapman
2010-03-18 10:21 ` [PATCH 01/12] l2tp: Relocate pppol2tp driver to new net/l2tp directory James Chapman
2010-03-18 10:21 ` [PATCH 02/12] l2tp: Split pppol2tp patch into separate l2tp and ppp parts James Chapman
2010-03-18 10:21 ` [PATCH 03/12] ppp: Add ppp_dev_name() exported function James Chapman
2010-03-18 10:21 ` [PATCH 04/12] l2tp: Add ppp device name to L2TP ppp session data James Chapman
2010-03-18 10:21 ` James Chapman [this message]
2010-03-18 10:21 ` [PATCH 06/12] l2tp: Update PPP-over-L2TP driver to work over L2TPv3 James Chapman
2010-03-18 10:22 ` [PATCH 07/12] l2tp: Add L2TPv3 IP encapsulation (no UDP) support James Chapman
2010-03-18 10:22 ` [PATCH 08/12] netlink: Export genl_lock() API for use by modules James Chapman
2010-03-18 16:00 ` Stephen Hemminger
2010-03-18 17:46 ` James Chapman
2010-03-18 10:22 ` [PATCH 09/12] l2tp: Add netlink control API for L2TP James Chapman
2010-03-18 10:22 ` [PATCH 10/12] l2tp: Add L2TP ethernet pseudowire support James Chapman
2010-03-18 10:22 ` [PATCH 11/12] l2tp: Add support for static unmanaged L2TPv3 tunnels James Chapman
2010-03-18 10:22 ` [PATCH 12/12] l2tp: Update documentation James Chapman
2010-03-18 15:52 ` Randy Dunlap
2010-03-20 6:23 ` [PATCH 00/12] l2tp: Introduce L2TPv3 support David Miller
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20100318102154.14576.28661.stgit@bert.katalix.com \
--to=jchapman@katalix.com \
--cc=netdev@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.