mirror of
https://github.com/ukui/kernel.git
synced 2026-03-09 10:07:04 -07:00
l2tp: Add L2TPv3 IP encapsulation (no UDP) support
This patch adds a new L2TPIP socket family and modifies the core to handle the case where there is no UDP header in the L2TP packet. L2TP/IP uses IP protocol 115. Since L2TP/UDP and L2TP/IP packets differ in layout, the datapath packet handling code needs changes too. Userspace uses an L2TPIP socket instead of a UDP socket when IP encapsulation is required. We can't use raw sockets for this because the semantics of raw sockets don't lend themselves to the socket-per-tunnel model - we need to Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
committed by
David S. Miller
parent
e0d4435f93
commit
0d76751fad
@@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
* L2TP-over-IP socket for L2TPv3.
|
||||||
|
*
|
||||||
|
* Author: James Chapman <jchapman@katalix.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _LINUX_L2TP_H_
|
||||||
|
#define _LINUX_L2TP_H_
|
||||||
|
|
||||||
|
#include <linux/types.h>
|
||||||
|
#ifdef __KERNEL__
|
||||||
|
#include <linux/socket.h>
|
||||||
|
#include <linux/in.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define IPPROTO_L2TP 115
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct sockaddr_l2tpip - the sockaddr structure for L2TP-over-IP sockets
|
||||||
|
* @l2tp_family: address family number AF_L2TPIP.
|
||||||
|
* @l2tp_addr: protocol specific address information
|
||||||
|
* @l2tp_conn_id: connection id of tunnel
|
||||||
|
*/
|
||||||
|
struct sockaddr_l2tpip {
|
||||||
|
/* The first fields must match struct sockaddr_in */
|
||||||
|
sa_family_t l2tp_family; /* AF_INET */
|
||||||
|
__be16 l2tp_unused; /* INET port number (unused) */
|
||||||
|
struct in_addr l2tp_addr; /* Internet address */
|
||||||
|
|
||||||
|
__u32 l2tp_conn_id; /* Connection ID of tunnel */
|
||||||
|
|
||||||
|
/* Pad to size of `struct sockaddr'. */
|
||||||
|
unsigned char __pad[sizeof(struct sockaddr) - sizeof(sa_family_t) -
|
||||||
|
sizeof(__be16) - sizeof(struct in_addr) -
|
||||||
|
sizeof(__u32)];
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -51,3 +51,20 @@ config L2TP_V3
|
|||||||
If you are connecting to L2TPv3 equipment, or you want to
|
If you are connecting to L2TPv3 equipment, or you want to
|
||||||
tunnel raw ethernet frames using L2TP, say Y here. If
|
tunnel raw ethernet frames using L2TP, say Y here. If
|
||||||
unsure, say N.
|
unsure, say N.
|
||||||
|
|
||||||
|
config L2TP_IP
|
||||||
|
tristate "L2TP IP encapsulation for L2TPv3"
|
||||||
|
depends on L2TP_V3
|
||||||
|
help
|
||||||
|
Support for L2TP-over-IP socket family.
|
||||||
|
|
||||||
|
The L2TPv3 protocol defines two possible encapsulations for
|
||||||
|
L2TP frames, namely UDP and plain IP (without UDP). This
|
||||||
|
driver provides a new L2TPIP socket family with which
|
||||||
|
userspace L2TPv3 daemons may create L2TP/IP tunnel sockets
|
||||||
|
when UDP encapsulation is not required. When L2TP is carried
|
||||||
|
in IP packets, it used IP protocol number 115, so this port
|
||||||
|
must be enabled in firewalls.
|
||||||
|
|
||||||
|
To compile this driver as a module, choose M here. The module
|
||||||
|
will be called l2tp_ip.
|
||||||
|
|||||||
@@ -6,3 +6,4 @@ obj-$(CONFIG_L2TP) += l2tp_core.o
|
|||||||
|
|
||||||
# Build l2tp as modules if L2TP is M
|
# Build l2tp as modules if L2TP is M
|
||||||
obj-$(subst y,$(CONFIG_L2TP),$(CONFIG_PPPOL2TP)) += l2tp_ppp.o
|
obj-$(subst y,$(CONFIG_L2TP),$(CONFIG_PPPOL2TP)) += l2tp_ppp.o
|
||||||
|
obj-$(subst y,$(CONFIG_L2TP),$(CONFIG_L2TP_IP)) += l2tp_ip.o
|
||||||
|
|||||||
+103
-60
@@ -36,8 +36,10 @@
|
|||||||
#include <linux/inetdevice.h>
|
#include <linux/inetdevice.h>
|
||||||
#include <linux/skbuff.h>
|
#include <linux/skbuff.h>
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
|
#include <linux/in.h>
|
||||||
#include <linux/ip.h>
|
#include <linux/ip.h>
|
||||||
#include <linux/udp.h>
|
#include <linux/udp.h>
|
||||||
|
#include <linux/l2tp.h>
|
||||||
#include <linux/hash.h>
|
#include <linux/hash.h>
|
||||||
#include <linux/sort.h>
|
#include <linux/sort.h>
|
||||||
#include <linux/file.h>
|
#include <linux/file.h>
|
||||||
@@ -48,6 +50,7 @@
|
|||||||
#include <net/ip.h>
|
#include <net/ip.h>
|
||||||
#include <net/udp.h>
|
#include <net/udp.h>
|
||||||
#include <net/xfrm.h>
|
#include <net/xfrm.h>
|
||||||
|
#include <net/protocol.h>
|
||||||
|
|
||||||
#include <asm/byteorder.h>
|
#include <asm/byteorder.h>
|
||||||
#include <asm/atomic.h>
|
#include <asm/atomic.h>
|
||||||
@@ -849,15 +852,21 @@ static int l2tp_build_l2tpv2_header(struct l2tp_session *session, void *buf)
|
|||||||
|
|
||||||
static int l2tp_build_l2tpv3_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 *bufp = buf;
|
||||||
char *optr = bufp;
|
char *optr = bufp;
|
||||||
u16 flags = L2TP_HDR_VER_3;
|
|
||||||
|
|
||||||
/* Setup L2TP header. */
|
/* Setup L2TP header. The header differs slightly for UDP and
|
||||||
*((__be16 *) bufp) = htons(flags);
|
* IP encapsulations. For UDP, there is 4 bytes of flags.
|
||||||
bufp += 2;
|
*/
|
||||||
*((__be16 *) bufp) = 0;
|
if (tunnel->encap == L2TP_ENCAPTYPE_UDP) {
|
||||||
bufp += 2;
|
u16 flags = L2TP_HDR_VER_3;
|
||||||
|
*((__be16 *) bufp) = htons(flags);
|
||||||
|
bufp += 2;
|
||||||
|
*((__be16 *) bufp) = 0;
|
||||||
|
bufp += 2;
|
||||||
|
}
|
||||||
|
|
||||||
*((__be32 *) bufp) = htonl(session->peer_session_id);
|
*((__be32 *) bufp) = htonl(session->peer_session_id);
|
||||||
bufp += 4;
|
bufp += 4;
|
||||||
if (session->cookie_len) {
|
if (session->cookie_len) {
|
||||||
@@ -902,10 +911,11 @@ int l2tp_xmit_core(struct l2tp_session *session, struct sk_buff *skb, size_t dat
|
|||||||
|
|
||||||
if (session->debug & L2TP_MSG_DATA) {
|
if (session->debug & L2TP_MSG_DATA) {
|
||||||
int i;
|
int i;
|
||||||
unsigned char *datap = skb->data + sizeof(struct udphdr);
|
int uhlen = (tunnel->encap == L2TP_ENCAPTYPE_UDP) ? sizeof(struct udphdr) : 0;
|
||||||
|
unsigned char *datap = skb->data + uhlen;
|
||||||
|
|
||||||
printk(KERN_DEBUG "%s: xmit:", session->name);
|
printk(KERN_DEBUG "%s: xmit:", session->name);
|
||||||
for (i = 0; i < (len - sizeof(struct udphdr)); i++) {
|
for (i = 0; i < (len - uhlen); i++) {
|
||||||
printk(" %02X", *datap++);
|
printk(" %02X", *datap++);
|
||||||
if (i == 31) {
|
if (i == 31) {
|
||||||
printk(" ...");
|
printk(" ...");
|
||||||
@@ -956,21 +966,23 @@ static inline void l2tp_skb_set_owner_w(struct sk_buff *skb, struct sock *sk)
|
|||||||
int l2tp_xmit_skb(struct l2tp_session *session, struct sk_buff *skb, int hdr_len)
|
int l2tp_xmit_skb(struct l2tp_session *session, struct sk_buff *skb, int hdr_len)
|
||||||
{
|
{
|
||||||
int data_len = skb->len;
|
int data_len = skb->len;
|
||||||
struct sock *sk = session->tunnel->sock;
|
struct l2tp_tunnel *tunnel = session->tunnel;
|
||||||
|
struct sock *sk = tunnel->sock;
|
||||||
struct udphdr *uh;
|
struct udphdr *uh;
|
||||||
unsigned int udp_len;
|
|
||||||
struct inet_sock *inet;
|
struct inet_sock *inet;
|
||||||
__wsum csum;
|
__wsum csum;
|
||||||
int old_headroom;
|
int old_headroom;
|
||||||
int new_headroom;
|
int new_headroom;
|
||||||
int headroom;
|
int headroom;
|
||||||
|
int uhlen = (tunnel->encap == L2TP_ENCAPTYPE_UDP) ? sizeof(struct udphdr) : 0;
|
||||||
|
int udp_len;
|
||||||
|
|
||||||
/* Check that there's enough headroom in the skb to insert IP,
|
/* Check that there's enough headroom in the skb to insert IP,
|
||||||
* UDP and L2TP headers. If not enough, expand it to
|
* UDP and L2TP headers. If not enough, expand it to
|
||||||
* make room. Adjust truesize.
|
* make room. Adjust truesize.
|
||||||
*/
|
*/
|
||||||
headroom = NET_SKB_PAD + sizeof(struct iphdr) +
|
headroom = NET_SKB_PAD + sizeof(struct iphdr) +
|
||||||
sizeof(struct udphdr) + hdr_len;
|
uhlen + hdr_len;
|
||||||
old_headroom = skb_headroom(skb);
|
old_headroom = skb_headroom(skb);
|
||||||
if (skb_cow_head(skb, headroom))
|
if (skb_cow_head(skb, headroom))
|
||||||
goto abort;
|
goto abort;
|
||||||
@@ -981,18 +993,8 @@ int l2tp_xmit_skb(struct l2tp_session *session, struct sk_buff *skb, int hdr_len
|
|||||||
|
|
||||||
/* Setup L2TP header */
|
/* Setup L2TP header */
|
||||||
session->build_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 */
|
|
||||||
inet = inet_sk(sk);
|
|
||||||
__skb_push(skb, sizeof(*uh));
|
|
||||||
skb_reset_transport_header(skb);
|
|
||||||
uh = udp_hdr(skb);
|
|
||||||
uh->source = inet->inet_sport;
|
|
||||||
uh->dest = inet->inet_dport;
|
|
||||||
uh->len = htons(udp_len);
|
|
||||||
uh->check = 0;
|
|
||||||
|
|
||||||
|
/* Reset skb netfilter state */
|
||||||
memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
|
memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
|
||||||
IPCB(skb)->flags &= ~(IPSKB_XFRM_TUNNEL_SIZE | IPSKB_XFRM_TRANSFORMED |
|
IPCB(skb)->flags &= ~(IPSKB_XFRM_TUNNEL_SIZE | IPSKB_XFRM_TRANSFORMED |
|
||||||
IPSKB_REROUTED);
|
IPSKB_REROUTED);
|
||||||
@@ -1001,29 +1003,48 @@ int l2tp_xmit_skb(struct l2tp_session *session, struct sk_buff *skb, int hdr_len
|
|||||||
/* Get routing info from the tunnel socket */
|
/* Get routing info from the tunnel socket */
|
||||||
skb_dst_drop(skb);
|
skb_dst_drop(skb);
|
||||||
skb_dst_set(skb, dst_clone(__sk_dst_get(sk)));
|
skb_dst_set(skb, dst_clone(__sk_dst_get(sk)));
|
||||||
l2tp_skb_set_owner_w(skb, sk);
|
|
||||||
|
|
||||||
/* Calculate UDP checksum if configured to do so */
|
switch (tunnel->encap) {
|
||||||
if (sk->sk_no_check == UDP_CSUM_NOXMIT)
|
case L2TP_ENCAPTYPE_UDP:
|
||||||
skb->ip_summed = CHECKSUM_NONE;
|
/* Setup UDP header */
|
||||||
else if ((skb_dst(skb) && skb_dst(skb)->dev) &&
|
inet = inet_sk(sk);
|
||||||
(!(skb_dst(skb)->dev->features & NETIF_F_V4_CSUM))) {
|
__skb_push(skb, sizeof(*uh));
|
||||||
skb->ip_summed = CHECKSUM_COMPLETE;
|
skb_reset_transport_header(skb);
|
||||||
csum = skb_checksum(skb, 0, udp_len, 0);
|
uh = udp_hdr(skb);
|
||||||
uh->check = csum_tcpudp_magic(inet->inet_saddr,
|
uh->source = inet->inet_sport;
|
||||||
inet->inet_daddr,
|
uh->dest = inet->inet_dport;
|
||||||
udp_len, IPPROTO_UDP, csum);
|
udp_len = uhlen + hdr_len + data_len;
|
||||||
if (uh->check == 0)
|
uh->len = htons(udp_len);
|
||||||
uh->check = CSUM_MANGLED_0;
|
uh->check = 0;
|
||||||
} else {
|
|
||||||
skb->ip_summed = CHECKSUM_PARTIAL;
|
/* Calculate UDP checksum if configured to do so */
|
||||||
skb->csum_start = skb_transport_header(skb) - skb->head;
|
if (sk->sk_no_check == UDP_CSUM_NOXMIT)
|
||||||
skb->csum_offset = offsetof(struct udphdr, check);
|
skb->ip_summed = CHECKSUM_NONE;
|
||||||
uh->check = ~csum_tcpudp_magic(inet->inet_saddr,
|
else if ((skb_dst(skb) && skb_dst(skb)->dev) &&
|
||||||
inet->inet_daddr,
|
(!(skb_dst(skb)->dev->features & NETIF_F_V4_CSUM))) {
|
||||||
udp_len, IPPROTO_UDP, 0);
|
skb->ip_summed = CHECKSUM_COMPLETE;
|
||||||
|
csum = skb_checksum(skb, 0, udp_len, 0);
|
||||||
|
uh->check = csum_tcpudp_magic(inet->inet_saddr,
|
||||||
|
inet->inet_daddr,
|
||||||
|
udp_len, IPPROTO_UDP, csum);
|
||||||
|
if (uh->check == 0)
|
||||||
|
uh->check = CSUM_MANGLED_0;
|
||||||
|
} else {
|
||||||
|
skb->ip_summed = CHECKSUM_PARTIAL;
|
||||||
|
skb->csum_start = skb_transport_header(skb) - skb->head;
|
||||||
|
skb->csum_offset = offsetof(struct udphdr, check);
|
||||||
|
uh->check = ~csum_tcpudp_magic(inet->inet_saddr,
|
||||||
|
inet->inet_daddr,
|
||||||
|
udp_len, IPPROTO_UDP, 0);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case L2TP_ENCAPTYPE_IP:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
l2tp_skb_set_owner_w(skb, sk);
|
||||||
|
|
||||||
l2tp_xmit_core(session, skb, data_len);
|
l2tp_xmit_core(session, skb, data_len);
|
||||||
|
|
||||||
abort:
|
abort:
|
||||||
@@ -1053,9 +1074,15 @@ void l2tp_tunnel_destruct(struct sock *sk)
|
|||||||
/* Close all sessions */
|
/* Close all sessions */
|
||||||
l2tp_tunnel_closeall(tunnel);
|
l2tp_tunnel_closeall(tunnel);
|
||||||
|
|
||||||
/* No longer an encapsulation socket. See net/ipv4/udp.c */
|
switch (tunnel->encap) {
|
||||||
(udp_sk(sk))->encap_type = 0;
|
case L2TP_ENCAPTYPE_UDP:
|
||||||
(udp_sk(sk))->encap_rcv = NULL;
|
/* No longer an encapsulation socket. See net/ipv4/udp.c */
|
||||||
|
(udp_sk(sk))->encap_type = 0;
|
||||||
|
(udp_sk(sk))->encap_rcv = NULL;
|
||||||
|
break;
|
||||||
|
case L2TP_ENCAPTYPE_IP:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
/* Remove hooks into tunnel socket */
|
/* Remove hooks into tunnel socket */
|
||||||
tunnel->sock = NULL;
|
tunnel->sock = NULL;
|
||||||
@@ -1168,6 +1195,7 @@ int l2tp_tunnel_create(struct net *net, int fd, int version, u32 tunnel_id, u32
|
|||||||
struct socket *sock = NULL;
|
struct socket *sock = NULL;
|
||||||
struct sock *sk = NULL;
|
struct sock *sk = NULL;
|
||||||
struct l2tp_net *pn;
|
struct l2tp_net *pn;
|
||||||
|
enum l2tp_encap_type encap = L2TP_ENCAPTYPE_UDP;
|
||||||
|
|
||||||
/* Get the tunnel socket from the fd, which was opened by
|
/* Get the tunnel socket from the fd, which was opened by
|
||||||
* the userspace L2TP daemon.
|
* the userspace L2TP daemon.
|
||||||
@@ -1182,18 +1210,27 @@ int l2tp_tunnel_create(struct net *net, int fd, int version, u32 tunnel_id, u32
|
|||||||
|
|
||||||
sk = sock->sk;
|
sk = sock->sk;
|
||||||
|
|
||||||
|
if (cfg != NULL)
|
||||||
|
encap = cfg->encap;
|
||||||
|
|
||||||
/* Quick sanity checks */
|
/* Quick sanity checks */
|
||||||
err = -EPROTONOSUPPORT;
|
switch (encap) {
|
||||||
if (sk->sk_protocol != IPPROTO_UDP) {
|
case L2TP_ENCAPTYPE_UDP:
|
||||||
printk(KERN_ERR "tunl %hu: fd %d wrong protocol, got %d, expected %d\n",
|
err = -EPROTONOSUPPORT;
|
||||||
tunnel_id, fd, sk->sk_protocol, IPPROTO_UDP);
|
if (sk->sk_protocol != IPPROTO_UDP) {
|
||||||
goto err;
|
printk(KERN_ERR "tunl %hu: fd %d wrong protocol, got %d, expected %d\n",
|
||||||
}
|
tunnel_id, fd, sk->sk_protocol, IPPROTO_UDP);
|
||||||
err = -EAFNOSUPPORT;
|
goto err;
|
||||||
if (sock->ops->family != AF_INET) {
|
}
|
||||||
printk(KERN_ERR "tunl %hu: fd %d wrong family, got %d, expected %d\n",
|
break;
|
||||||
tunnel_id, fd, sock->ops->family, AF_INET);
|
case L2TP_ENCAPTYPE_IP:
|
||||||
goto err;
|
err = -EPROTONOSUPPORT;
|
||||||
|
if (sk->sk_protocol != IPPROTO_L2TP) {
|
||||||
|
printk(KERN_ERR "tunl %hu: fd %d wrong protocol, got %d, expected %d\n",
|
||||||
|
tunnel_id, fd, sk->sk_protocol, IPPROTO_L2TP);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check if this socket has already been prepped */
|
/* Check if this socket has already been prepped */
|
||||||
@@ -1223,12 +1260,16 @@ int l2tp_tunnel_create(struct net *net, int fd, int version, u32 tunnel_id, u32
|
|||||||
tunnel->l2tp_net = net;
|
tunnel->l2tp_net = net;
|
||||||
pn = l2tp_pernet(net);
|
pn = l2tp_pernet(net);
|
||||||
|
|
||||||
if (cfg)
|
if (cfg != NULL)
|
||||||
tunnel->debug = cfg->debug;
|
tunnel->debug = cfg->debug;
|
||||||
|
|
||||||
/* Mark socket as an encapsulation socket. See net/ipv4/udp.c */
|
/* Mark socket as an encapsulation socket. See net/ipv4/udp.c */
|
||||||
udp_sk(sk)->encap_type = UDP_ENCAP_L2TPINUDP;
|
tunnel->encap = encap;
|
||||||
udp_sk(sk)->encap_rcv = l2tp_udp_encap_recv;
|
if (encap == L2TP_ENCAPTYPE_UDP) {
|
||||||
|
/* Mark socket as an encapsulation socket. See net/ipv4/udp.c */
|
||||||
|
udp_sk(sk)->encap_type = UDP_ENCAP_L2TPINUDP;
|
||||||
|
udp_sk(sk)->encap_rcv = l2tp_udp_encap_recv;
|
||||||
|
}
|
||||||
|
|
||||||
sk->sk_user_data = tunnel;
|
sk->sk_user_data = tunnel;
|
||||||
|
|
||||||
@@ -1318,7 +1359,9 @@ void l2tp_session_set_header_len(struct l2tp_session *session, int version)
|
|||||||
if (session->send_seq)
|
if (session->send_seq)
|
||||||
session->hdr_len += 4;
|
session->hdr_len += 4;
|
||||||
} else {
|
} else {
|
||||||
session->hdr_len = 8 + session->cookie_len + session->l2specific_len + session->offset;
|
session->hdr_len = 4 + session->cookie_len + session->l2specific_len + session->offset;
|
||||||
|
if (session->tunnel->encap == L2TP_ENCAPTYPE_UDP)
|
||||||
|
session->hdr_len += 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,6 +48,11 @@ enum l2tp_l2spec_type {
|
|||||||
L2TP_L2SPECTYPE_DEFAULT,
|
L2TP_L2SPECTYPE_DEFAULT,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum l2tp_encap_type {
|
||||||
|
L2TP_ENCAPTYPE_UDP,
|
||||||
|
L2TP_ENCAPTYPE_IP,
|
||||||
|
};
|
||||||
|
|
||||||
struct sk_buff;
|
struct sk_buff;
|
||||||
|
|
||||||
struct l2tp_stats {
|
struct l2tp_stats {
|
||||||
@@ -155,6 +160,7 @@ struct l2tp_session {
|
|||||||
struct l2tp_tunnel_cfg {
|
struct l2tp_tunnel_cfg {
|
||||||
int debug; /* bitmask of debug message
|
int debug; /* bitmask of debug message
|
||||||
* categories */
|
* categories */
|
||||||
|
enum l2tp_encap_type encap;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct l2tp_tunnel {
|
struct l2tp_tunnel {
|
||||||
@@ -170,6 +176,7 @@ struct l2tp_tunnel {
|
|||||||
char name[20]; /* for logging */
|
char name[20]; /* for logging */
|
||||||
int debug; /* bitmask of debug message
|
int debug; /* bitmask of debug message
|
||||||
* categories */
|
* categories */
|
||||||
|
enum l2tp_encap_type encap;
|
||||||
struct l2tp_stats stats;
|
struct l2tp_stats stats;
|
||||||
|
|
||||||
struct list_head list; /* Keep a list of all tunnels */
|
struct list_head list; /* Keep a list of all tunnels */
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
+5
-2
@@ -305,6 +305,7 @@ static int pppol2tp_sendmsg(struct kiocb *iocb, struct socket *sock, struct msgh
|
|||||||
struct l2tp_session *session;
|
struct l2tp_session *session;
|
||||||
struct l2tp_tunnel *tunnel;
|
struct l2tp_tunnel *tunnel;
|
||||||
struct pppol2tp_session *ps;
|
struct pppol2tp_session *ps;
|
||||||
|
int uhlen;
|
||||||
|
|
||||||
error = -ENOTCONN;
|
error = -ENOTCONN;
|
||||||
if (sock_flag(sk, SOCK_DEAD) || !(sk->sk_state & PPPOX_CONNECTED))
|
if (sock_flag(sk, SOCK_DEAD) || !(sk->sk_state & PPPOX_CONNECTED))
|
||||||
@@ -321,10 +322,12 @@ static int pppol2tp_sendmsg(struct kiocb *iocb, struct socket *sock, struct msgh
|
|||||||
if (tunnel == NULL)
|
if (tunnel == NULL)
|
||||||
goto error_put_sess;
|
goto error_put_sess;
|
||||||
|
|
||||||
|
uhlen = (tunnel->encap == L2TP_ENCAPTYPE_UDP) ? sizeof(struct udphdr) : 0;
|
||||||
|
|
||||||
/* Allocate a socket buffer */
|
/* Allocate a socket buffer */
|
||||||
error = -ENOMEM;
|
error = -ENOMEM;
|
||||||
skb = sock_wmalloc(sk, NET_SKB_PAD + sizeof(struct iphdr) +
|
skb = sock_wmalloc(sk, NET_SKB_PAD + sizeof(struct iphdr) +
|
||||||
sizeof(struct udphdr) + session->hdr_len +
|
uhlen + session->hdr_len +
|
||||||
sizeof(ppph) + total_len,
|
sizeof(ppph) + total_len,
|
||||||
0, GFP_KERNEL);
|
0, GFP_KERNEL);
|
||||||
if (!skb)
|
if (!skb)
|
||||||
@@ -335,7 +338,7 @@ static int pppol2tp_sendmsg(struct kiocb *iocb, struct socket *sock, struct msgh
|
|||||||
skb_reset_network_header(skb);
|
skb_reset_network_header(skb);
|
||||||
skb_reserve(skb, sizeof(struct iphdr));
|
skb_reserve(skb, sizeof(struct iphdr));
|
||||||
skb_reset_transport_header(skb);
|
skb_reset_transport_header(skb);
|
||||||
skb_reserve(skb, sizeof(struct udphdr));
|
skb_reserve(skb, uhlen);
|
||||||
|
|
||||||
/* Add PPP header */
|
/* Add PPP header */
|
||||||
skb->data[0] = ppph[0];
|
skb->data[0] = ppph[0];
|
||||||
|
|||||||
Reference in New Issue
Block a user