Commit 08aaa081 authored by David S. Miller's avatar David S. Miller

Merge branch 'l2tp-miscellaneous-cleanups'

Tom Parkin says:

====================
l2tp: miscellaneous cleanups

This series of patches makes the following cleanups and improvements to
the l2tp code:

 * various API tweaks to remove unused parameters from function calls
 * lightly refactor the l2tp transmission path to capture more error
   conditions in the data plane statistics
 * repurpose the "magic feather" validation in l2tp to check for
   sk_user_data (ab)use as opposed to refcount debugging
 * remove some duplicated code
====================
Reviewed-by: default avatarJames Chapman <jchapman@katalix.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents ffd923f5 9d319a8e
...@@ -120,11 +120,6 @@ static bool l2tp_sk_is_v6(struct sock *sk) ...@@ -120,11 +120,6 @@ static bool l2tp_sk_is_v6(struct sock *sk)
} }
#endif #endif
static inline struct l2tp_tunnel *l2tp_tunnel(struct sock *sk)
{
return sk->sk_user_data;
}
static inline struct l2tp_net *l2tp_pernet(const struct net *net) static inline struct l2tp_net *l2tp_pernet(const struct net *net)
{ {
return net_generic(net, l2tp_net_id); return net_generic(net, l2tp_net_id);
...@@ -162,19 +157,23 @@ static void l2tp_tunnel_free(struct l2tp_tunnel *tunnel) ...@@ -162,19 +157,23 @@ static void l2tp_tunnel_free(struct l2tp_tunnel *tunnel)
static void l2tp_session_free(struct l2tp_session *session) static void l2tp_session_free(struct l2tp_session *session)
{ {
struct l2tp_tunnel *tunnel = session->tunnel;
trace_free_session(session); trace_free_session(session);
if (session->tunnel)
l2tp_tunnel_dec_refcount(session->tunnel);
kfree(session);
}
if (tunnel) { struct l2tp_tunnel *l2tp_sk_to_tunnel(struct sock *sk)
{
struct l2tp_tunnel *tunnel = sk->sk_user_data;
if (tunnel)
if (WARN_ON(tunnel->magic != L2TP_TUNNEL_MAGIC)) if (WARN_ON(tunnel->magic != L2TP_TUNNEL_MAGIC))
goto out; return NULL;
l2tp_tunnel_dec_refcount(tunnel);
}
out: return tunnel;
kfree(session);
} }
EXPORT_SYMBOL_GPL(l2tp_sk_to_tunnel);
void l2tp_tunnel_inc_refcount(struct l2tp_tunnel *tunnel) void l2tp_tunnel_inc_refcount(struct l2tp_tunnel *tunnel)
{ {
...@@ -782,9 +781,6 @@ static void l2tp_session_queue_purge(struct l2tp_session *session) ...@@ -782,9 +781,6 @@ static void l2tp_session_queue_purge(struct l2tp_session *session)
{ {
struct sk_buff *skb = NULL; struct sk_buff *skb = NULL;
if (WARN_ON(session->magic != L2TP_SESSION_MAGIC))
return;
while ((skb = skb_dequeue(&session->reorder_q))) { while ((skb = skb_dequeue(&session->reorder_q))) {
atomic_long_inc(&session->stats.rx_errors); atomic_long_inc(&session->stats.rx_errors);
kfree_skb(skb); kfree_skb(skb);
...@@ -898,9 +894,17 @@ int l2tp_udp_encap_recv(struct sock *sk, struct sk_buff *skb) ...@@ -898,9 +894,17 @@ int l2tp_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
{ {
struct l2tp_tunnel *tunnel; struct l2tp_tunnel *tunnel;
/* Note that this is called from the encap_rcv hook inside an
* RCU-protected region, but without the socket being locked.
* Hence we use rcu_dereference_sk_user_data to access the
* tunnel data structure rather the usual l2tp_sk_to_tunnel
* accessor function.
*/
tunnel = rcu_dereference_sk_user_data(sk); tunnel = rcu_dereference_sk_user_data(sk);
if (!tunnel) if (!tunnel)
goto pass_up; goto pass_up;
if (WARN_ON(tunnel->magic != L2TP_TUNNEL_MAGIC))
goto pass_up;
if (l2tp_udp_recv_core(tunnel, skb)) if (l2tp_udp_recv_core(tunnel, skb))
goto pass_up; goto pass_up;
...@@ -985,57 +989,39 @@ static int l2tp_build_l2tpv3_header(struct l2tp_session *session, void *buf) ...@@ -985,57 +989,39 @@ static int l2tp_build_l2tpv3_header(struct l2tp_session *session, void *buf)
return bufp - optr; return bufp - optr;
} }
static void l2tp_xmit_core(struct l2tp_session *session, struct sk_buff *skb, /* Queue the packet to IP for output: tunnel socket lock must be held */
struct flowi *fl, size_t data_len) static int l2tp_xmit_queue(struct l2tp_tunnel *tunnel, struct sk_buff *skb, struct flowi *fl)
{ {
struct l2tp_tunnel *tunnel = session->tunnel; int err;
unsigned int len = skb->len;
int error;
/* Queue the packet to IP for output */
skb->ignore_df = 1; skb->ignore_df = 1;
skb_dst_drop(skb); skb_dst_drop(skb);
#if IS_ENABLED(CONFIG_IPV6) #if IS_ENABLED(CONFIG_IPV6)
if (l2tp_sk_is_v6(tunnel->sock)) if (l2tp_sk_is_v6(tunnel->sock))
error = inet6_csk_xmit(tunnel->sock, skb, NULL); err = inet6_csk_xmit(tunnel->sock, skb, NULL);
else else
#endif #endif
error = ip_queue_xmit(tunnel->sock, skb, fl); err = ip_queue_xmit(tunnel->sock, skb, fl);
/* Update stats */ return err >= 0 ? NET_XMIT_SUCCESS : NET_XMIT_DROP;
if (error >= 0) {
atomic_long_inc(&tunnel->stats.tx_packets);
atomic_long_add(len, &tunnel->stats.tx_bytes);
atomic_long_inc(&session->stats.tx_packets);
atomic_long_add(len, &session->stats.tx_bytes);
} else {
atomic_long_inc(&tunnel->stats.tx_errors);
atomic_long_inc(&session->stats.tx_errors);
}
} }
/* If caller requires the skb to have a ppp header, the header must be static int l2tp_xmit_core(struct l2tp_session *session, struct sk_buff *skb)
* inserted in the skb data before calling this function.
*/
int l2tp_xmit_skb(struct l2tp_session *session, struct sk_buff *skb, int hdr_len)
{ {
int data_len = skb->len;
struct l2tp_tunnel *tunnel = session->tunnel; struct l2tp_tunnel *tunnel = session->tunnel;
unsigned int data_len = skb->len;
struct sock *sk = tunnel->sock; struct sock *sk = tunnel->sock;
struct flowi *fl; int headroom, uhlen, udp_len;
struct udphdr *uh;
struct inet_sock *inet;
int headroom;
int uhlen = (tunnel->encap == L2TP_ENCAPTYPE_UDP) ? sizeof(struct udphdr) : 0;
int udp_len;
int ret = NET_XMIT_SUCCESS; int ret = NET_XMIT_SUCCESS;
struct inet_sock *inet;
struct udphdr *uh;
/* 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) + uhlen = (tunnel->encap == L2TP_ENCAPTYPE_UDP) ? sizeof(*uh) : 0;
uhlen + hdr_len; headroom = NET_SKB_PAD + sizeof(struct iphdr) + uhlen + session->hdr_len;
if (skb_cow_head(skb, headroom)) { if (skb_cow_head(skb, headroom)) {
kfree_skb(skb); kfree_skb(skb);
return NET_XMIT_DROP; return NET_XMIT_DROP;
...@@ -1043,14 +1029,13 @@ int l2tp_xmit_skb(struct l2tp_session *session, struct sk_buff *skb, int hdr_len ...@@ -1043,14 +1029,13 @@ int l2tp_xmit_skb(struct l2tp_session *session, struct sk_buff *skb, int hdr_len
/* Setup L2TP header */ /* Setup L2TP header */
if (tunnel->version == L2TP_HDR_VER_2) if (tunnel->version == L2TP_HDR_VER_2)
l2tp_build_l2tpv2_header(session, __skb_push(skb, hdr_len)); l2tp_build_l2tpv2_header(session, __skb_push(skb, session->hdr_len));
else else
l2tp_build_l2tpv3_header(session, __skb_push(skb, hdr_len)); l2tp_build_l2tpv3_header(session, __skb_push(skb, session->hdr_len));
/* Reset skb netfilter state */ /* 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);
nf_reset_ct(skb); nf_reset_ct(skb);
bh_lock_sock(sk); bh_lock_sock(sk);
...@@ -1070,7 +1055,6 @@ int l2tp_xmit_skb(struct l2tp_session *session, struct sk_buff *skb, int hdr_len ...@@ -1070,7 +1055,6 @@ int l2tp_xmit_skb(struct l2tp_session *session, struct sk_buff *skb, int hdr_len
} }
inet = inet_sk(sk); inet = inet_sk(sk);
fl = &inet->cork.fl;
switch (tunnel->encap) { switch (tunnel->encap) {
case L2TP_ENCAPTYPE_UDP: case L2TP_ENCAPTYPE_UDP:
/* Setup UDP header */ /* Setup UDP header */
...@@ -1079,7 +1063,7 @@ int l2tp_xmit_skb(struct l2tp_session *session, struct sk_buff *skb, int hdr_len ...@@ -1079,7 +1063,7 @@ int l2tp_xmit_skb(struct l2tp_session *session, struct sk_buff *skb, int hdr_len
uh = udp_hdr(skb); uh = udp_hdr(skb);
uh->source = inet->inet_sport; uh->source = inet->inet_sport;
uh->dest = inet->inet_dport; uh->dest = inet->inet_dport;
udp_len = uhlen + hdr_len + data_len; udp_len = uhlen + session->hdr_len + data_len;
uh->len = htons(udp_len); uh->len = htons(udp_len);
/* Calculate UDP checksum if configured to do so */ /* Calculate UDP checksum if configured to do so */
...@@ -1098,12 +1082,34 @@ int l2tp_xmit_skb(struct l2tp_session *session, struct sk_buff *skb, int hdr_len ...@@ -1098,12 +1082,34 @@ int l2tp_xmit_skb(struct l2tp_session *session, struct sk_buff *skb, int hdr_len
break; break;
} }
l2tp_xmit_core(session, skb, fl, data_len); ret = l2tp_xmit_queue(tunnel, skb, &inet->cork.fl);
out_unlock: out_unlock:
bh_unlock_sock(sk); bh_unlock_sock(sk);
return ret; return ret;
} }
/* If caller requires the skb to have a ppp header, the header must be
* inserted in the skb data before calling this function.
*/
int l2tp_xmit_skb(struct l2tp_session *session, struct sk_buff *skb)
{
unsigned int len = skb->len;
int ret;
ret = l2tp_xmit_core(session, skb);
if (ret == NET_XMIT_SUCCESS) {
atomic_long_inc(&session->tunnel->stats.tx_packets);
atomic_long_add(len, &session->tunnel->stats.tx_bytes);
atomic_long_inc(&session->stats.tx_packets);
atomic_long_add(len, &session->stats.tx_bytes);
} else {
atomic_long_inc(&session->tunnel->stats.tx_errors);
atomic_long_inc(&session->stats.tx_errors);
}
return ret;
}
EXPORT_SYMBOL_GPL(l2tp_xmit_skb); EXPORT_SYMBOL_GPL(l2tp_xmit_skb);
/***************************************************************************** /*****************************************************************************
...@@ -1116,7 +1122,7 @@ EXPORT_SYMBOL_GPL(l2tp_xmit_skb); ...@@ -1116,7 +1122,7 @@ EXPORT_SYMBOL_GPL(l2tp_xmit_skb);
*/ */
static void l2tp_tunnel_destruct(struct sock *sk) static void l2tp_tunnel_destruct(struct sock *sk)
{ {
struct l2tp_tunnel *tunnel = l2tp_tunnel(sk); struct l2tp_tunnel *tunnel = l2tp_sk_to_tunnel(sk);
if (!tunnel) if (!tunnel)
goto end; goto end;
...@@ -1185,22 +1191,10 @@ static void l2tp_tunnel_closeall(struct l2tp_tunnel *tunnel) ...@@ -1185,22 +1191,10 @@ static void l2tp_tunnel_closeall(struct l2tp_tunnel *tunnel)
again: again:
hlist_for_each_safe(walk, tmp, &tunnel->session_hlist[hash]) { hlist_for_each_safe(walk, tmp, &tunnel->session_hlist[hash]) {
session = hlist_entry(walk, struct l2tp_session, hlist); session = hlist_entry(walk, struct l2tp_session, hlist);
hlist_del_init(&session->hlist); hlist_del_init(&session->hlist);
if (test_and_set_bit(0, &session->dead))
goto again;
write_unlock_bh(&tunnel->hlist_lock); write_unlock_bh(&tunnel->hlist_lock);
l2tp_session_delete(session);
l2tp_session_unhash(session);
l2tp_session_queue_purge(session);
if (session->session_close)
(*session->session_close)(session);
l2tp_session_dec_refcount(session);
write_lock_bh(&tunnel->hlist_lock); write_lock_bh(&tunnel->hlist_lock);
/* Now restart from the beginning of this hash /* Now restart from the beginning of this hash
...@@ -1217,7 +1211,7 @@ static void l2tp_tunnel_closeall(struct l2tp_tunnel *tunnel) ...@@ -1217,7 +1211,7 @@ static void l2tp_tunnel_closeall(struct l2tp_tunnel *tunnel)
/* Tunnel socket destroy hook for UDP encapsulation */ /* Tunnel socket destroy hook for UDP encapsulation */
static void l2tp_udp_encap_destroy(struct sock *sk) static void l2tp_udp_encap_destroy(struct sock *sk)
{ {
struct l2tp_tunnel *tunnel = l2tp_tunnel(sk); struct l2tp_tunnel *tunnel = l2tp_sk_to_tunnel(sk);
if (tunnel) if (tunnel)
l2tp_tunnel_delete(tunnel); l2tp_tunnel_delete(tunnel);
...@@ -1382,7 +1376,7 @@ static int l2tp_tunnel_sock_create(struct net *net, ...@@ -1382,7 +1376,7 @@ static int l2tp_tunnel_sock_create(struct net *net,
static struct lock_class_key l2tp_socket_class; static struct lock_class_key l2tp_socket_class;
int l2tp_tunnel_create(struct net *net, int fd, int version, u32 tunnel_id, u32 peer_tunnel_id, int l2tp_tunnel_create(int fd, int version, u32 tunnel_id, u32 peer_tunnel_id,
struct l2tp_tunnel_cfg *cfg, struct l2tp_tunnel **tunnelp) struct l2tp_tunnel_cfg *cfg, struct l2tp_tunnel **tunnelp)
{ {
struct l2tp_tunnel *tunnel = NULL; struct l2tp_tunnel *tunnel = NULL;
......
...@@ -235,7 +235,7 @@ struct l2tp_session *l2tp_session_get_by_ifname(const struct net *net, ...@@ -235,7 +235,7 @@ struct l2tp_session *l2tp_session_get_by_ifname(const struct net *net,
* Creation of a new instance is a two-step process: create, then register. * Creation of a new instance is a two-step process: create, then register.
* Destruction is triggered using the *_delete functions, and completes asynchronously. * Destruction is triggered using the *_delete functions, and completes asynchronously.
*/ */
int l2tp_tunnel_create(struct net *net, int fd, int version, u32 tunnel_id, int l2tp_tunnel_create(int fd, int version, u32 tunnel_id,
u32 peer_tunnel_id, struct l2tp_tunnel_cfg *cfg, u32 peer_tunnel_id, struct l2tp_tunnel_cfg *cfg,
struct l2tp_tunnel **tunnelp); struct l2tp_tunnel **tunnelp);
int l2tp_tunnel_register(struct l2tp_tunnel *tunnel, struct net *net, int l2tp_tunnel_register(struct l2tp_tunnel *tunnel, struct net *net,
...@@ -261,8 +261,7 @@ int l2tp_udp_encap_recv(struct sock *sk, struct sk_buff *skb); ...@@ -261,8 +261,7 @@ int l2tp_udp_encap_recv(struct sock *sk, struct sk_buff *skb);
/* Transmit path helpers for sending packets over the tunnel socket. */ /* Transmit path helpers for sending packets over the tunnel socket. */
void l2tp_session_set_header_len(struct l2tp_session *session, int version); void l2tp_session_set_header_len(struct l2tp_session *session, int version);
int l2tp_xmit_skb(struct l2tp_session *session, struct sk_buff *skb, int l2tp_xmit_skb(struct l2tp_session *session, struct sk_buff *skb);
int hdr_len);
/* Pseudowire management. /* Pseudowire management.
* Pseudowires should register with l2tp core on module init, and unregister * Pseudowires should register with l2tp core on module init, and unregister
...@@ -274,6 +273,11 @@ void l2tp_nl_unregister_ops(enum l2tp_pwtype pw_type); ...@@ -274,6 +273,11 @@ void l2tp_nl_unregister_ops(enum l2tp_pwtype pw_type);
/* IOCTL helper for IP encap modules. */ /* IOCTL helper for IP encap modules. */
int l2tp_ioctl(struct sock *sk, int cmd, unsigned long arg); int l2tp_ioctl(struct sock *sk, int cmd, unsigned long arg);
/* Extract the tunnel structure from a socket's sk_user_data pointer,
* validating the tunnel magic feather.
*/
struct l2tp_tunnel *l2tp_sk_to_tunnel(struct sock *sk);
static inline int l2tp_get_l2specific_len(struct l2tp_session *session) static inline int l2tp_get_l2specific_len(struct l2tp_session *session)
{ {
switch (session->l2specific_type) { switch (session->l2specific_type) {
......
...@@ -76,7 +76,7 @@ static netdev_tx_t l2tp_eth_dev_xmit(struct sk_buff *skb, struct net_device *dev ...@@ -76,7 +76,7 @@ static netdev_tx_t l2tp_eth_dev_xmit(struct sk_buff *skb, struct net_device *dev
struct l2tp_eth *priv = netdev_priv(dev); struct l2tp_eth *priv = netdev_priv(dev);
struct l2tp_session *session = priv->session; struct l2tp_session *session = priv->session;
unsigned int len = skb->len; unsigned int len = skb->len;
int ret = l2tp_xmit_skb(session, skb, session->hdr_len); int ret = l2tp_xmit_skb(session, skb);
if (likely(ret == NET_XMIT_SUCCESS)) { if (likely(ret == NET_XMIT_SUCCESS)) {
atomic_long_add(len, &priv->tx_bytes); atomic_long_add(len, &priv->tx_bytes);
......
...@@ -233,8 +233,8 @@ static void l2tp_ip_close(struct sock *sk, long timeout) ...@@ -233,8 +233,8 @@ static void l2tp_ip_close(struct sock *sk, long timeout)
static void l2tp_ip_destroy_sock(struct sock *sk) static void l2tp_ip_destroy_sock(struct sock *sk)
{ {
struct l2tp_tunnel *tunnel = l2tp_sk_to_tunnel(sk);
struct sk_buff *skb; struct sk_buff *skb;
struct l2tp_tunnel *tunnel = sk->sk_user_data;
while ((skb = __skb_dequeue_tail(&sk->sk_write_queue)) != NULL) while ((skb = __skb_dequeue_tail(&sk->sk_write_queue)) != NULL)
kfree_skb(skb); kfree_skb(skb);
......
...@@ -247,7 +247,7 @@ static void l2tp_ip6_close(struct sock *sk, long timeout) ...@@ -247,7 +247,7 @@ static void l2tp_ip6_close(struct sock *sk, long timeout)
static void l2tp_ip6_destroy_sock(struct sock *sk) static void l2tp_ip6_destroy_sock(struct sock *sk)
{ {
struct l2tp_tunnel *tunnel = sk->sk_user_data; struct l2tp_tunnel *tunnel = l2tp_sk_to_tunnel(sk);
lock_sock(sk); lock_sock(sk);
ip6_flush_pending_frames(sk); ip6_flush_pending_frames(sk);
......
...@@ -233,7 +233,7 @@ static int l2tp_nl_cmd_tunnel_create(struct sk_buff *skb, struct genl_info *info ...@@ -233,7 +233,7 @@ static int l2tp_nl_cmd_tunnel_create(struct sk_buff *skb, struct genl_info *info
switch (cfg.encap) { switch (cfg.encap) {
case L2TP_ENCAPTYPE_UDP: case L2TP_ENCAPTYPE_UDP:
case L2TP_ENCAPTYPE_IP: case L2TP_ENCAPTYPE_IP:
ret = l2tp_tunnel_create(net, fd, proto_version, tunnel_id, ret = l2tp_tunnel_create(fd, proto_version, tunnel_id,
peer_tunnel_id, &cfg, &tunnel); peer_tunnel_id, &cfg, &tunnel);
break; break;
} }
......
...@@ -316,7 +316,7 @@ static int pppol2tp_sendmsg(struct socket *sock, struct msghdr *m, ...@@ -316,7 +316,7 @@ static int pppol2tp_sendmsg(struct socket *sock, struct msghdr *m,
} }
local_bh_disable(); local_bh_disable();
l2tp_xmit_skb(session, skb, session->hdr_len); l2tp_xmit_skb(session, skb);
local_bh_enable(); local_bh_enable();
sock_put(sk); sock_put(sk);
...@@ -375,7 +375,7 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb) ...@@ -375,7 +375,7 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb)
skb->data[1] = PPP_UI; skb->data[1] = PPP_UI;
local_bh_disable(); local_bh_disable();
l2tp_xmit_skb(session, skb, session->hdr_len); l2tp_xmit_skb(session, skb);
local_bh_enable(); local_bh_enable();
sock_put(sk); sock_put(sk);
...@@ -712,7 +712,7 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr, ...@@ -712,7 +712,7 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr,
goto end; goto end;
} }
error = l2tp_tunnel_create(sock_net(sk), info.fd, error = l2tp_tunnel_create(info.fd,
info.version, info.version,
info.tunnel_id, info.tunnel_id,
info.peer_tunnel_id, &tcfg, info.peer_tunnel_id, &tcfg,
...@@ -1065,6 +1065,9 @@ static int pppol2tp_ioctl(struct socket *sock, unsigned int cmd, ...@@ -1065,6 +1065,9 @@ static int pppol2tp_ioctl(struct socket *sock, unsigned int cmd,
if (!session) if (!session)
return -ENOTCONN; return -ENOTCONN;
if (WARN_ON(session->magic != L2TP_SESSION_MAGIC))
return -EBADF;
/* Not defined for tunnels */ /* Not defined for tunnels */
if (!session->session_id && !session->peer_session_id) if (!session->session_id && !session->peer_session_id)
return -ENOSYS; return -ENOSYS;
...@@ -1079,6 +1082,9 @@ static int pppol2tp_ioctl(struct socket *sock, unsigned int cmd, ...@@ -1079,6 +1082,9 @@ static int pppol2tp_ioctl(struct socket *sock, unsigned int cmd,
if (!session) if (!session)
return -ENOTCONN; return -ENOTCONN;
if (WARN_ON(session->magic != L2TP_SESSION_MAGIC))
return -EBADF;
/* Not defined for tunnels */ /* Not defined for tunnels */
if (!session->session_id && !session->peer_session_id) if (!session->session_id && !session->peer_session_id)
return -ENOSYS; return -ENOSYS;
...@@ -1092,6 +1098,9 @@ static int pppol2tp_ioctl(struct socket *sock, unsigned int cmd, ...@@ -1092,6 +1098,9 @@ static int pppol2tp_ioctl(struct socket *sock, unsigned int cmd,
if (!session) if (!session)
return -ENOTCONN; return -ENOTCONN;
if (WARN_ON(session->magic != L2TP_SESSION_MAGIC))
return -EBADF;
/* Session 0 represents the parent tunnel */ /* Session 0 represents the parent tunnel */
if (!session->session_id && !session->peer_session_id) { if (!session->session_id && !session->peer_session_id) {
u32 session_id; u32 session_id;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment