if (sk == NULL)
return NULL;
+ sock_hold(sk);
session = (struct pppol2tp_session *)(sk->sk_user_data);
- if (session == NULL)
- return NULL;
+ if (session == NULL) {
+ sock_put(sk);
+ goto out;
+ }
BUG_ON(session->magic != L2TP_SESSION_MAGIC);
-
+out:
return session;
}
if (sk == NULL)
return NULL;
+ sock_hold(sk);
tunnel = (struct pppol2tp_tunnel *)(sk->sk_user_data);
- if (tunnel == NULL)
- return NULL;
+ if (tunnel == NULL) {
+ sock_put(sk);
+ goto out;
+ }
BUG_ON(tunnel->magic != L2TP_TUNNEL_MAGIC);
-
+out:
return tunnel;
}
session->stats.rx_errors++;
kfree_skb(skb);
sock_put(session->sock);
+ sock_put(sock);
return 0;
error:
/* Put UDP header back */
__skb_push(skb, sizeof(struct udphdr));
+ sock_put(sock);
no_tunnel:
return 1;
"%s: received %d bytes\n", tunnel->name, skb->len);
if (pppol2tp_recv_core(sk, skb))
- goto pass_up;
+ goto pass_up_put;
+ sock_put(sk);
return 0;
+pass_up_put:
+ sock_put(sk);
pass_up:
return 1;
}
tunnel = pppol2tp_sock_to_tunnel(session->tunnel_sock);
if (tunnel == NULL)
- goto error;
+ goto error_put_sess;
/* What header length is configured for this session? */
hdr_len = pppol2tp_l2tp_header_len(session);
sizeof(ppph) + total_len,
0, GFP_KERNEL);
if (!skb)
- goto error;
+ goto error_put_sess_tun;
/* Reserve space for headers. */
skb_reserve(skb, NET_SKB_PAD);
error = memcpy_fromiovec(skb->data, m->msg_iov, total_len);
if (error < 0) {
kfree_skb(skb);
- goto error;
+ goto error_put_sess_tun;
}
skb_put(skb, total_len);
session->stats.tx_errors++;
}
+ return error;
+
+error_put_sess_tun:
+ sock_put(session->tunnel_sock);
+error_put_sess:
+ sock_put(sk);
error:
return error;
}
+/* Automatically called when the skb is freed.
+ */
+static void pppol2tp_sock_wfree(struct sk_buff *skb)
+{
+ sock_put(skb->sk);
+}
+
+/* For data skbs that we transmit, we associate with the tunnel socket
+ * but don't do accounting.
+ */
+static inline void pppol2tp_skb_set_owner_w(struct sk_buff *skb, struct sock *sk)
+{
+ sock_hold(sk);
+ skb->sk = sk;
+ skb->destructor = pppol2tp_sock_wfree;
+}
+
/* Transmit function called by generic PPP driver. Sends PPP frame
* over PPPoL2TP socket.
*
sk_tun = session->tunnel_sock;
if (sk_tun == NULL)
- goto abort;
+ goto abort_put_sess;
tunnel = pppol2tp_sock_to_tunnel(sk_tun);
if (tunnel == NULL)
- goto abort;
+ goto abort_put_sess;
/* What header length is configured for this session? */
hdr_len = pppol2tp_l2tp_header_len(session);
sizeof(struct udphdr) + hdr_len + sizeof(ppph);
old_headroom = skb_headroom(skb);
if (skb_cow_head(skb, headroom))
- goto abort;
+ goto abort_put_sess_tun;
new_headroom = skb_headroom(skb);
skb_orphan(skb);
/* Get routing info from the tunnel socket */
dst_release(skb->dst);
skb->dst = dst_clone(__sk_dst_get(sk_tun));
- skb->sk = sk_tun;
+ pppol2tp_skb_set_owner_w(skb, sk_tun);
/* Queue the packet to IP for output */
len = skb->len;
session->stats.tx_errors++;
}
+ sock_put(sk_tun);
+ sock_put(sk);
return 1;
+abort_put_sess_tun:
+ sock_put(sk_tun);
+abort_put_sess:
+ sock_put(sk);
abort:
/* Free the original skb */
kfree_skb(skb);
{
struct pppol2tp_tunnel *tunnel;
- tunnel = pppol2tp_sock_to_tunnel(sk);
+ tunnel = sk->sk_user_data;
if (tunnel == NULL)
goto end;
if (sk->sk_user_data != NULL) {
struct pppol2tp_tunnel *tunnel;
- session = pppol2tp_sock_to_session(sk);
+ session = sk->sk_user_data;
if (session == NULL)
goto out;
+ BUG_ON(session->magic != L2TP_SESSION_MAGIC);
+
/* Don't use pppol2tp_sock_to_tunnel() here to
* get the tunnel context because the tunnel
* socket might have already been closed (its
error = ppp_register_channel(&po->chan);
if (error)
- goto end;
+ goto end_put_tun;
/* This is how we get the session context from the socket. */
sk->sk_user_data = session;
PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO,
"%s: created\n", session->name);
+end_put_tun:
+ sock_put(tunnel_sock);
end:
release_sock(sk);
*usockaddr_len = len;
error = 0;
+ sock_put(sock->sk);
end:
return error;
err = -EBADF;
tunnel = pppol2tp_sock_to_tunnel(session->tunnel_sock);
if (tunnel == NULL)
- goto end;
+ goto end_put_sess;
err = pppol2tp_tunnel_ioctl(tunnel, cmd, arg);
- goto end;
+ sock_put(session->tunnel_sock);
+ goto end_put_sess;
}
err = pppol2tp_session_ioctl(session, cmd, arg);
+end_put_sess:
+ sock_put(sk);
end:
return err;
}
err = -EBADF;
tunnel = pppol2tp_sock_to_tunnel(session->tunnel_sock);
if (tunnel == NULL)
- goto end;
+ goto end_put_sess;
err = pppol2tp_tunnel_setsockopt(sk, tunnel, optname, val);
+ sock_put(session->tunnel_sock);
} else
err = pppol2tp_session_setsockopt(sk, session, optname, val);
err = 0;
+end_put_sess:
+ sock_put(sk);
end:
return err;
}
err = -EBADF;
tunnel = pppol2tp_sock_to_tunnel(session->tunnel_sock);
if (tunnel == NULL)
- goto end;
+ goto end_put_sess;
err = pppol2tp_tunnel_getsockopt(sk, tunnel, optname, &val);
+ sock_put(session->tunnel_sock);
} else
err = pppol2tp_session_getsockopt(sk, session, optname, &val);
err = -EFAULT;
if (put_user(len, (int __user *) optlen))
- goto end;
+ goto end_put_sess;
if (copy_to_user((void __user *) optval, &val, len))
- goto end;
+ goto end_put_sess;
err = 0;
+
+end_put_sess:
+ sock_put(sk);
end:
return err;
}