]> nv-tegra.nvidia Code Review - linux-2.6.git/blobdiff - drivers/net/pppol2tp.c
netns: net_identifiers should be read_mostly
[linux-2.6.git] / drivers / net / pppol2tp.c
index f87176055d0ee6430ddc1fff6b09dea781ebd5b2..442c382c2c850f4940f49cd0bbb63ae14d10e717 100644 (file)
@@ -61,7 +61,6 @@
  */
 
 #include <linux/module.h>
-#include <linux/version.h>
 #include <linux/string.h>
 #include <linux/list.h>
 #include <asm/uaccess.h>
@@ -91,6 +90,9 @@
 #include <linux/hash.h>
 #include <linux/sort.h>
 #include <linux/proc_fs.h>
+#include <linux/nsproxy.h>
+#include <net/net_namespace.h>
+#include <net/netns/generic.h>
 #include <net/dst.h>
 #include <net/ip.h>
 #include <net/udp.h>
@@ -204,6 +206,7 @@ struct pppol2tp_tunnel
        struct sock             *sock;          /* Parent socket */
        struct list_head        list;           /* Keep a list of all open
                                                 * prepared sockets */
+       struct net              *pppol2tp_net;  /* the net we belong to */
 
        atomic_t                ref_count;
 };
@@ -226,9 +229,21 @@ 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);
+static const struct proto_ops pppol2tp_ops;
+
+/* per-net private data for this module */
+static int pppol2tp_net_id __read_mostly;
+struct pppol2tp_net {
+       struct list_head pppol2tp_tunnel_list;
+       rwlock_t pppol2tp_tunnel_list_lock;
+};
+
+static inline struct pppol2tp_net *pppol2tp_pernet(struct net *net)
+{
+       BUG_ON(!net);
+
+       return net_generic(net, pppol2tp_net_id);
+}
 
 /* Helpers to obtain tunnel/session contexts from sockets.
  */
@@ -239,12 +254,15 @@ static inline struct pppol2tp_session *pppol2tp_sock_to_session(struct sock *sk)
        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;
 }
 
@@ -255,12 +273,15 @@ static inline struct pppol2tp_tunnel *pppol2tp_sock_to_tunnel(struct sock *sk)
        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;
 }
 
@@ -301,32 +322,33 @@ pppol2tp_session_find(struct pppol2tp_tunnel *tunnel, u16 session_id)
        struct pppol2tp_session *session;
        struct hlist_node *walk;
 
-       read_lock(&tunnel->hlist_lock);
+       read_lock_bh(&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);
+                       read_unlock_bh(&tunnel->hlist_lock);
                        return session;
                }
        }
-       read_unlock(&tunnel->hlist_lock);
+       read_unlock_bh(&tunnel->hlist_lock);
 
        return NULL;
 }
 
 /* Lookup a tunnel by id
  */
-static struct pppol2tp_tunnel *pppol2tp_tunnel_find(u16 tunnel_id)
+static struct pppol2tp_tunnel *pppol2tp_tunnel_find(struct net *net, u16 tunnel_id)
 {
-       struct pppol2tp_tunnel *tunnel = NULL;
+       struct pppol2tp_tunnel *tunnel;
+       struct pppol2tp_net *pn = pppol2tp_pernet(net);
 
-       read_lock(&pppol2tp_tunnel_list_lock);
-       list_for_each_entry(tunnel, &pppol2tp_tunnel_list, list) {
+       read_lock_bh(&pn->pppol2tp_tunnel_list_lock);
+       list_for_each_entry(tunnel, &pn->pppol2tp_tunnel_list, list) {
                if (tunnel->stats.tunnel_id == tunnel_id) {
-                       read_unlock(&pppol2tp_tunnel_list_lock);
+                       read_unlock_bh(&pn->pppol2tp_tunnel_list_lock);
                        return tunnel;
                }
        }
-       read_unlock(&pppol2tp_tunnel_list_lock);
+       read_unlock_bh(&pn->pppol2tp_tunnel_list_lock);
 
        return NULL;
 }
@@ -341,12 +363,13 @@ static struct pppol2tp_tunnel *pppol2tp_tunnel_find(u16 tunnel_id)
 static void pppol2tp_recv_queue_skb(struct pppol2tp_session *session, struct sk_buff *skb)
 {
        struct sk_buff *skbp;
+       struct sk_buff *tmp;
        u16 ns = PPPOL2TP_SKB_CB(skb)->ns;
 
-       spin_lock(&session->reorder_q.lock);
-       skb_queue_walk(&session->reorder_q, skbp) {
+       spin_lock_bh(&session->reorder_q.lock);
+       skb_queue_walk_safe(&session->reorder_q, skbp, tmp) {
                if (PPPOL2TP_SKB_CB(skbp)->ns > ns) {
-                       __skb_insert(skb, skbp->prev, skbp, &session->reorder_q);
+                       __skb_queue_before(&session->reorder_q, skbp, skb);
                        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,
@@ -359,7 +382,7 @@ static void pppol2tp_recv_queue_skb(struct pppol2tp_session *session, struct sk_
        __skb_queue_tail(&session->reorder_q, skb);
 
 out:
-       spin_unlock(&session->reorder_q.lock);
+       spin_unlock_bh(&session->reorder_q.lock);
 }
 
 /* Dequeue a single skb.
@@ -370,10 +393,9 @@ static void pppol2tp_recv_dequeue_skb(struct pppol2tp_session *session, struct s
        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
+       /* We're about to requeue the skb, so return resources
         * to its current owner (a socket receive buffer).
         */
-       skb_unlink(skb, &session->reorder_q);
        skb_orphan(skb);
 
        tunnel->stats.rx_packets++;
@@ -411,8 +433,7 @@ static void pppol2tp_recv_dequeue_skb(struct pppol2tp_session *session, struct s
                 *   to the inner packet either
                 */
                secpath_reset(skb);
-               dst_release(skb->dst);
-               skb->dst = NULL;
+               skb_dst_drop(skb);
                nf_reset(skb);
 
                po = pppox_sk(session_sock);
@@ -441,7 +462,7 @@ static void pppol2tp_recv_dequeue(struct pppol2tp_session *session)
         * expect to send up next, dequeue it and any other
         * in-sequence packets behind it.
         */
-       spin_lock(&session->reorder_q.lock);
+       spin_lock_bh(&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++;
@@ -454,6 +475,7 @@ static void pppol2tp_recv_dequeue(struct pppol2tp_session *session)
                               skb_queue_len(&session->reorder_q));
                        __skb_unlink(skb, &session->reorder_q);
                        kfree_skb(skb);
+                       sock_put(session->sock);
                        continue;
                }
 
@@ -468,13 +490,42 @@ static void pppol2tp_recv_dequeue(struct pppol2tp_session *session)
                                goto out;
                        }
                }
-               spin_unlock(&session->reorder_q.lock);
+               __skb_unlink(skb, &session->reorder_q);
+
+               /* Process the skb. We release the queue lock while we
+                * do so to let other contexts process the queue.
+                */
+               spin_unlock_bh(&session->reorder_q.lock);
                pppol2tp_recv_dequeue_skb(session, skb);
-               spin_lock(&session->reorder_q.lock);
+               spin_lock_bh(&session->reorder_q.lock);
        }
 
 out:
-       spin_unlock(&session->reorder_q.lock);
+       spin_unlock_bh(&session->reorder_q.lock);
+}
+
+static inline int pppol2tp_verify_udp_checksum(struct sock *sk,
+                                              struct sk_buff *skb)
+{
+       struct udphdr *uh = udp_hdr(skb);
+       u16 ulen = ntohs(uh->len);
+       struct inet_sock *inet;
+       __wsum psum;
+
+       if (sk->sk_no_check || skb_csum_unnecessary(skb) || !uh->check)
+               return 0;
+
+       inet = inet_sk(sk);
+       psum = csum_tcpudp_nofold(inet->inet_saddr, inet->inet_daddr, ulen,
+                                 IPPROTO_UDP, 0);
+
+       if ((skb->ip_summed == CHECKSUM_COMPLETE) &&
+           !csum_fold(csum_add(psum, skb->csum)))
+               return 0;
+
+       skb->csum = psum;
+
+       return __skb_checksum_complete(skb);
 }
 
 /* Internal receive frame. Do the real work of receiving an L2TP data frame
@@ -487,48 +538,53 @@ static int pppol2tp_recv_core(struct sock *sock, struct sk_buff *skb)
 {
        struct pppol2tp_session *session = NULL;
        struct pppol2tp_tunnel *tunnel;
-       unsigned char *ptr;
+       unsigned char *ptr, *optr;
        u16 hdrflags;
        u16 tunnel_id, session_id;
        int length;
-       struct udphdr *uh;
+       int offset;
 
        tunnel = pppol2tp_sock_to_tunnel(sock);
        if (tunnel == NULL)
-               goto error;
+               goto no_tunnel;
+
+       if (tunnel->sock && pppol2tp_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 (skb->len < sizeof(struct udphdr)) {
+       if (!pskb_may_pull(skb, 12)) {
                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);
+       optr = ptr = skb->data;
 
        /* Get L2TP header flags */
        hdrflags = ntohs(*(__be16*)ptr);
 
        /* Trace packet contents, if enabled */
        if (tunnel->debug & PPPOL2TP_MSG_DATA) {
+               length = min(16u, skb->len);
+               if (!pskb_may_pull(skb, length))
+                       goto error;
+
                printk(KERN_DEBUG "%s: recv: ", tunnel->name);
 
-               for (length = 0; length < 16; length++)
-                       printk(" %02X", ptr[length]);
+               offset = 0;
+               do {
+                       printk(" %02X", ptr[offset]);
+               } while (++offset < 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;
-       }
+       length = skb->len;
 
        /* If type is control packet, it is handled by userspace. */
        if (hdrflags & L2TP_HDRFLAG_T) {
@@ -606,7 +662,6 @@ static int pppol2tp_recv_core(struct sock *sock, struct sk_buff *skb)
                               "%s: recv data has no seq numbers when required. "
                               "Discarding\n", session->name);
                        session->stats.rx_seq_discards++;
-                       session->stats.rx_errors++;
                        goto discard;
                }
 
@@ -625,7 +680,6 @@ static int pppol2tp_recv_core(struct sock *sock, struct sk_buff *skb)
                               "%s: recv data has no seq numbers when required. "
                               "Discarding\n", session->name);
                        session->stats.rx_seq_discards++;
-                       session->stats.rx_errors++;
                        goto discard;
                }
 
@@ -634,10 +688,16 @@ static int pppol2tp_recv_core(struct sock *sock, struct sk_buff *skb)
        }
 
        /* If offset bit set, skip it. */
-       if (hdrflags & L2TP_HDRFLAG_O)
-               ptr += 2 + ntohs(*(__be16 *) ptr);
+       if (hdrflags & L2TP_HDRFLAG_O) {
+               offset = ntohs(*(__be16 *)ptr);
+               ptr += 2 + offset;
+       }
 
-       skb_pull(skb, ptr - skb->data);
+       offset = ptr - optr;
+       if (!pskb_may_pull(skb, offset))
+               goto discard;
+
+       __skb_pull(skb, offset);
 
        /* Skip PPP header, if present.  In testing, Microsoft L2TP clients
         * don't send the PPP header (PPP header compression enabled), but
@@ -647,6 +707,9 @@ static int pppol2tp_recv_core(struct sock *sock, struct sk_buff *skb)
         * Note that skb->data[] isn't dereferenced from a u16 ptr here since
         * the field may be unaligned.
         */
+       if (!pskb_may_pull(skb, 2))
+               goto discard;
+
        if ((skb->data[0] == 0xff) && (skb->data[1] == 0x03))
                skb_pull(skb, 2);
 
@@ -673,7 +736,6 @@ static int pppol2tp_recv_core(struct sock *sock, struct sk_buff *skb)
                         */
                        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",
@@ -698,12 +760,27 @@ static int pppol2tp_recv_core(struct sock *sock, struct sk_buff *skb)
        return 0;
 
 discard:
+       session->stats.rx_errors++;
        kfree_skb(skb);
        sock_put(session->sock);
+       sock_put(sock);
+
+       return 0;
+
+discard_bad_csum:
+       LIMIT_NETDEBUG("%s: UDP: bad checksum\n", tunnel->name);
+       UDP_INC_STATS_USER(&init_net, UDP_MIB_INERRORS, 0);
+       tunnel->stats.rx_errors++;
+       kfree_skb(skb);
 
        return 0;
 
 error:
+       /* Put UDP header back */
+       __skb_push(skb, sizeof(struct udphdr));
+       sock_put(sock);
+
+no_tunnel:
        return 1;
 }
 
@@ -725,10 +802,13 @@ static int pppol2tp_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
               "%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;
 }
@@ -752,14 +832,18 @@ static int pppol2tp_recvmsg(struct kiocb *iocb, struct socket *sock,
        err = 0;
        skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT,
                                flags & MSG_DONTWAIT, &err);
-       if (skb) {
-               err = memcpy_toiovec(msg->msg_iov, (unsigned char *) skb->data,
-                                    skb->len);
-               if (err < 0)
-                       goto do_skb_free;
-               err = skb->len;
-       }
-do_skb_free:
+       if (!skb)
+               goto end;
+
+       if (len > skb->len)
+               len = skb->len;
+       else if (len < skb->len)
+               msg->msg_flags |= MSG_TRUNC;
+
+       err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, len);
+       if (likely(err == 0))
+               err = len;
+
        kfree_skb(skb);
 end:
        return err;
@@ -817,7 +901,7 @@ static int pppol2tp_sendmsg(struct kiocb *iocb, struct socket *sock, struct msgh
        static const unsigned char ppph[2] = { 0xff, 0x03 };
        struct sock *sk = sock->sk;
        struct inet_sock *inet;
-       __wsum csum = 0;
+       __wsum csum;
        struct sk_buff *skb;
        int error;
        int hdr_len;
@@ -825,6 +909,8 @@ static int pppol2tp_sendmsg(struct kiocb *iocb, struct socket *sock, struct msgh
        struct pppol2tp_tunnel *tunnel;
        struct udphdr *uh;
        unsigned int len;
+       struct sock *sk_tun;
+       u16 udp_len;
 
        error = -ENOTCONN;
        if (sock_flag(sk, SOCK_DEAD) || !(sk->sk_state & PPPOX_CONNECTED))
@@ -836,9 +922,10 @@ static int pppol2tp_sendmsg(struct kiocb *iocb, struct socket *sock, struct msgh
        if (session == NULL)
                goto error;
 
-       tunnel = pppol2tp_sock_to_tunnel(session->tunnel_sock);
+       sk_tun = session->tunnel_sock;
+       tunnel = pppol2tp_sock_to_tunnel(sk_tun);
        if (tunnel == NULL)
-               goto error;
+               goto error_put_sess;
 
        /* What header length is configured for this session? */
        hdr_len = pppol2tp_l2tp_header_len(session);
@@ -850,7 +937,7 @@ static int pppol2tp_sendmsg(struct kiocb *iocb, struct socket *sock, struct msgh
                           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);
@@ -859,11 +946,12 @@ static int pppol2tp_sendmsg(struct kiocb *iocb, struct socket *sock, struct msgh
        skb_reset_transport_header(skb);
 
        /* Build UDP header */
-       inet = inet_sk(session->tunnel_sock);
+       inet = inet_sk(sk_tun);
+       udp_len = hdr_len + sizeof(ppph) + total_len;
        uh = (struct udphdr *) skb->data;
-       uh->source = inet->sport;
-       uh->dest = inet->dport;
-       uh->len = htons(hdr_len + sizeof(ppph) + total_len);
+       uh->source = inet->inet_sport;
+       uh->dest = inet->inet_dport;
+       uh->len = htons(udp_len);
        uh->check = 0;
        skb_put(skb, sizeof(struct udphdr));
 
@@ -880,13 +968,29 @@ static int pppol2tp_sendmsg(struct kiocb *iocb, struct socket *sock, struct msgh
        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);
 
        /* Calculate UDP checksum if configured to do so */
-       if (session->tunnel_sock->sk_no_check != UDP_CSUM_NOXMIT)
-               csum = udp_csum_outgoing(sk, skb);
+       if (sk_tun->sk_no_check == UDP_CSUM_NOXMIT)
+               skb->ip_summed = CHECKSUM_NONE;
+       else if (!(skb_dst(skb)->dev->features & NETIF_F_V4_CSUM)) {
+               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);
+       }
 
        /* Debug */
        if (session->send_seq)
@@ -927,10 +1031,33 @@ static int pppol2tp_sendmsg(struct kiocb *iocb, struct socket *sock, struct msgh
                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.
  *
@@ -951,16 +1078,18 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb)
        struct sock *sk = (struct sock *) chan->private;
        struct sock *sk_tun;
        int hdr_len;
+       u16 udp_len;
        struct pppol2tp_session *session;
        struct pppol2tp_tunnel *tunnel;
        int rc;
        int headroom;
        int data_len = skb->len;
        struct inet_sock *inet;
-       __wsum csum = 0;
-       struct sk_buff *skb2 = NULL;
+       __wsum csum;
        struct udphdr *uh;
        unsigned int len;
+       int old_headroom;
+       int new_headroom;
 
        if (sock_flag(sk, SOCK_DEAD) || !(sk->sk_state & PPPOX_CONNECTED))
                goto abort;
@@ -972,59 +1101,48 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb)
 
        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);
 
        /* Check that there's enough headroom in the skb to insert IP,
         * UDP and L2TP and PPP headers. If not enough, expand it to
-        * make room. Note that a new skb (or a clone) is
-        * allocated. If we return an error from this point on, make
-        * sure we free the new skb but do not free the original skb
-        * since that is done by the caller for the error case.
+        * make room. Adjust truesize.
         */
        headroom = NET_SKB_PAD + sizeof(struct iphdr) +
                sizeof(struct udphdr) + hdr_len + sizeof(ppph);
-       if (skb_headroom(skb) < headroom) {
-               skb2 = skb_realloc_headroom(skb, headroom);
-               if (skb2 == NULL)
-                       goto abort;
-       } else
-               skb2 = skb;
+       old_headroom = skb_headroom(skb);
+       if (skb_cow_head(skb, headroom))
+               goto abort_put_sess_tun;
 
-       /* Check that the socket has room */
-       if (atomic_read(&sk_tun->sk_wmem_alloc) < sk_tun->sk_sndbuf)
-               skb_set_owner_w(skb2, sk_tun);
-       else
-               goto discard;
+       new_headroom = skb_headroom(skb);
+       skb_orphan(skb);
+       skb->truesize += new_headroom - old_headroom;
 
        /* Setup PPP header */
-       skb_push(skb2, sizeof(ppph));
-       skb2->data[0] = ppph[0];
-       skb2->data[1] = ppph[1];
+       __skb_push(skb, sizeof(ppph));
+       skb->data[0] = ppph[0];
+       skb->data[1] = ppph[1];
 
        /* Setup L2TP header */
-       skb_push(skb2, hdr_len);
-       pppol2tp_build_l2tp_header(session, skb2->data);
+       pppol2tp_build_l2tp_header(session, __skb_push(skb, hdr_len));
+
+       udp_len = sizeof(struct udphdr) + hdr_len + sizeof(ppph) + data_len;
 
        /* Setup UDP header */
        inet = inet_sk(sk_tun);
-       skb_push(skb2, sizeof(struct udphdr));
-       skb_reset_transport_header(skb2);
-       uh = (struct udphdr *) skb2->data;
-       uh->source = inet->sport;
-       uh->dest = inet->dport;
-       uh->len = htons(sizeof(struct udphdr) + hdr_len + sizeof(ppph) + data_len);
+       __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;
 
-       /* Calculate UDP checksum if configured to do so */
-       if (sk_tun->sk_no_check != UDP_CSUM_NOXMIT)
-               csum = udp_csum_outgoing(sk_tun, skb2);
-
        /* Debug */
        if (session->send_seq)
                PRINTK(session->debug, PPPOL2TP_MSG_DATA, KERN_DEBUG,
@@ -1036,7 +1154,7 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb)
 
        if (session->debug & PPPOL2TP_MSG_DATA) {
                int i;
-               unsigned char *datap = skb2->data;
+               unsigned char *datap = skb->data;
 
                printk(KERN_DEBUG "%s: xmit:", session->name);
                for (i = 0; i < data_len; i++) {
@@ -1049,18 +1167,39 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb)
                printk("\n");
        }
 
-       memset(&(IPCB(skb2)->opt), 0, sizeof(IPCB(skb2)->opt));
-       IPCB(skb2)->flags &= ~(IPSKB_XFRM_TUNNEL_SIZE | IPSKB_XFRM_TRANSFORMED |
-                              IPSKB_REROUTED);
-       nf_reset(skb2);
+       memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
+       IPCB(skb)->flags &= ~(IPSKB_XFRM_TUNNEL_SIZE | IPSKB_XFRM_TRANSFORMED |
+                             IPSKB_REROUTED);
+       nf_reset(skb);
 
        /* Get routing info from the tunnel socket */
-       dst_release(skb2->dst);
-       skb2->dst = sk_dst_get(sk_tun);
+       skb_dst_drop(skb);
+       skb_dst_set(skb, dst_clone(__sk_dst_get(sk_tun)));
+       pppol2tp_skb_set_owner_w(skb, sk_tun);
+
+       /* Calculate UDP checksum if configured to do so */
+       if (sk_tun->sk_no_check == UDP_CSUM_NOXMIT)
+               skb->ip_summed = CHECKSUM_NONE;
+       else if (!(skb_dst(skb)->dev->features & NETIF_F_V4_CSUM)) {
+               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);
+       }
 
        /* Queue the packet to IP for output */
-       len = skb2->len;
-       rc = ip_queue_xmit(skb2, 1);
+       len = skb->len;
+       rc = ip_queue_xmit(skb, 1);
 
        /* Update stats */
        if (rc >= 0) {
@@ -1073,17 +1212,18 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb)
                session->stats.tx_errors++;
        }
 
-       /* Free the original skb */
-       kfree_skb(skb);
-
+       sock_put(sk_tun);
+       sock_put(sk);
        return 1;
 
-discard:
-       /* Free the new skb. Caller will free original skb. */
-       if (skb2 != skb)
-               kfree_skb(skb2);
+abort_put_sess_tun:
+       sock_put(sk_tun);
+abort_put_sess:
+       sock_put(sk);
 abort:
-       return 0;
+       /* Free the original skb */
+       kfree_skb(skb);
+       return 1;
 }
 
 /*****************************************************************************
@@ -1101,16 +1241,17 @@ static void pppol2tp_tunnel_closeall(struct pppol2tp_tunnel *tunnel)
        struct pppol2tp_session *session;
        struct sock *sk;
 
-       if (tunnel == NULL)
-               BUG();
+       BUG_ON(tunnel == NULL);
 
        PRINTK(tunnel->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO,
               "%s: closing all sessions...\n", tunnel->name);
 
-       write_lock(&tunnel->hlist_lock);
+       write_lock_bh(&tunnel->hlist_lock);
        for (hash = 0; hash < PPPOL2TP_HASH_SIZE; hash++) {
 again:
                hlist_for_each_safe(walk, tmp, &tunnel->session_hlist[hash]) {
+                       struct sk_buff *skb;
+
                        session = hlist_entry(walk, struct pppol2tp_session, hlist);
 
                        sk = session->sock;
@@ -1127,7 +1268,7 @@ again:
                         * disappear as we're jumping between locks.
                         */
                        sock_hold(sk);
-                       write_unlock(&tunnel->hlist_lock);
+                       write_unlock_bh(&tunnel->hlist_lock);
                        lock_sock(sk);
 
                        if (sk->sk_state & (PPPOX_CONNECTED | PPPOX_BOUND)) {
@@ -1139,7 +1280,10 @@ again:
                        /* Purge any queued data */
                        skb_queue_purge(&sk->sk_receive_queue);
                        skb_queue_purge(&sk->sk_write_queue);
-                       skb_queue_purge(&session->reorder_q);
+                       while ((skb = skb_dequeue(&session->reorder_q))) {
+                               kfree_skb(skb);
+                               sock_put(sk);
+                       }
 
                        release_sock(sk);
                        sock_put(sk);
@@ -1149,11 +1293,11 @@ again:
                         * list so we are guaranteed to make forward
                         * progress.
                         */
-                       write_lock(&tunnel->hlist_lock);
+                       write_lock_bh(&tunnel->hlist_lock);
                        goto again;
                }
        }
-       write_unlock(&tunnel->hlist_lock);
+       write_unlock_bh(&tunnel->hlist_lock);
 }
 
 /* Really kill the tunnel.
@@ -1161,10 +1305,12 @@ again:
  */
 static void pppol2tp_tunnel_free(struct pppol2tp_tunnel *tunnel)
 {
+       struct pppol2tp_net *pn = pppol2tp_pernet(tunnel->pppol2tp_net);
+
        /* Remove from socket list */
-       write_lock(&pppol2tp_tunnel_list_lock);
+       write_lock_bh(&pn->pppol2tp_tunnel_list_lock);
        list_del_init(&tunnel->list);
-       write_unlock(&pppol2tp_tunnel_list_lock);
+       write_unlock_bh(&pn->pppol2tp_tunnel_list_lock);
 
        atomic_dec(&pppol2tp_tunnel_count);
        kfree(tunnel);
@@ -1178,7 +1324,7 @@ static void pppol2tp_tunnel_destruct(struct sock *sk)
 {
        struct pppol2tp_tunnel *tunnel;
 
-       tunnel = pppol2tp_sock_to_tunnel(sk);
+       tunnel = sk->sk_user_data;
        if (tunnel == NULL)
                goto end;
 
@@ -1217,10 +1363,12 @@ static void pppol2tp_session_destruct(struct sock *sk)
        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
@@ -1240,9 +1388,9 @@ static void pppol2tp_session_destruct(struct sock *sk)
                                /* Delete the session socket from the
                                 * hash
                                 */
-                               write_lock(&tunnel->hlist_lock);
+                               write_lock_bh(&tunnel->hlist_lock);
                                hlist_del_init(&session->hlist);
-                               write_unlock(&tunnel->hlist_lock);
+                               write_unlock_bh(&tunnel->hlist_lock);
 
                                atomic_dec(&pppol2tp_session_count);
                        }
@@ -1266,6 +1414,7 @@ out:
 static int pppol2tp_release(struct socket *sock)
 {
        struct sock *sk = sock->sk;
+       struct pppol2tp_session *session;
        int error;
 
        if (!sk)
@@ -1283,9 +1432,19 @@ static int pppol2tp_release(struct socket *sock)
        sock_orphan(sk);
        sock->sk = NULL;
 
+       session = pppol2tp_sock_to_session(sk);
+
        /* Purge any queued data */
        skb_queue_purge(&sk->sk_receive_queue);
        skb_queue_purge(&sk->sk_write_queue);
+       if (session != NULL) {
+               struct sk_buff *skb;
+               while ((skb = skb_dequeue(&session->reorder_q))) {
+                       kfree_skb(skb);
+                       sock_put(sk);
+               }
+               sock_put(sk);
+       }
 
        release_sock(sk);
 
@@ -1305,13 +1464,14 @@ error:
 /* Internal function to prepare a tunnel (UDP) socket to have PPPoX
  * sockets attached to it.
  */
-static struct sock *pppol2tp_prepare_tunnel_socket(int fd, u16 tunnel_id,
-                                                  int *error)
+static struct sock *pppol2tp_prepare_tunnel_socket(struct net *net,
+                                       int fd, u16 tunnel_id, int *error)
 {
        int err;
        struct socket *sock = NULL;
        struct sock *sk;
        struct pppol2tp_tunnel *tunnel;
+       struct pppol2tp_net *pn;
        struct sock *ret = NULL;
 
        /* Get the tunnel UDP socket from the fd, which was opened by
@@ -1326,12 +1486,14 @@ static struct sock *pppol2tp_prepare_tunnel_socket(int fd, u16 tunnel_id,
                goto err;
        }
 
+       sk = sock->sk;
+
        /* Quick sanity checks */
-       err = -ESOCKTNOSUPPORT;
-       if (sock->type != SOCK_DGRAM) {
+       err = -EPROTONOSUPPORT;
+       if (sk->sk_protocol != IPPROTO_UDP) {
                PRINTK(-1, PPPOL2TP_MSG_CONTROL, KERN_ERR,
-                      "tunl %hu: fd %d wrong type, got %d, expected %d\n",
-                      tunnel_id, fd, sock->type, SOCK_DGRAM);
+                      "tunl %hu: fd %d wrong protocol, got %d, expected %d\n",
+                      tunnel_id, fd, sk->sk_protocol, IPPROTO_UDP);
                goto err;
        }
        err = -EAFNOSUPPORT;
@@ -1343,7 +1505,6 @@ static struct sock *pppol2tp_prepare_tunnel_socket(int fd, u16 tunnel_id,
        }
 
        err = -ENOTCONN;
-       sk = sock->sk;
 
        /* Check if this socket has already been prepped */
        tunnel = (struct pppol2tp_tunnel *)sk->sk_user_data;
@@ -1384,11 +1545,15 @@ static struct sock *pppol2tp_prepare_tunnel_socket(int fd, u16 tunnel_id,
        /* Misc init */
        rwlock_init(&tunnel->hlist_lock);
 
+       /* The net we belong to */
+       tunnel->pppol2tp_net = net;
+       pn = pppol2tp_pernet(net);
+
        /* Add tunnel to our list */
        INIT_LIST_HEAD(&tunnel->list);
-       write_lock(&pppol2tp_tunnel_list_lock);
-       list_add(&tunnel->list, &pppol2tp_tunnel_list);
-       write_unlock(&pppol2tp_tunnel_list_lock);
+       write_lock_bh(&pn->pppol2tp_tunnel_list_lock);
+       list_add(&tunnel->list, &pn->pppol2tp_tunnel_list);
+       write_unlock_bh(&pn->pppol2tp_tunnel_list_lock);
        atomic_inc(&pppol2tp_tunnel_count);
 
        /* Bump the reference count. The tunnel context is deleted
@@ -1422,12 +1587,12 @@ static struct proto pppol2tp_sk_proto = {
 
 /* socket() handler. Initialize a new struct sock.
  */
-static int pppol2tp_create(struct socket *sock)
+static int pppol2tp_create(struct net *net, struct socket *sock)
 {
        int error = -ENOMEM;
        struct sock *sk;
 
-       sk = sk_alloc(PF_PPPOX, GFP_KERNEL, &pppol2tp_sk_proto, 1);
+       sk = sk_alloc(net, PF_PPPOX, GFP_KERNEL, &pppol2tp_sk_proto);
        if (!sk)
                goto out;
 
@@ -1489,7 +1654,8 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr,
         * tunnel id.
         */
        if ((sp->pppol2tp.s_session == 0) && (sp->pppol2tp.d_session == 0)) {
-               tunnel_sock = pppol2tp_prepare_tunnel_socket(sp->pppol2tp.fd,
+               tunnel_sock = pppol2tp_prepare_tunnel_socket(sock_net(sk),
+                                                            sp->pppol2tp.fd,
                                                             sp->pppol2tp.s_tunnel,
                                                             &error);
                if (tunnel_sock == NULL)
@@ -1497,7 +1663,7 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr,
 
                tunnel = tunnel_sock->sk_user_data;
        } else {
-               tunnel = pppol2tp_tunnel_find(sp->pppol2tp.s_tunnel);
+               tunnel = pppol2tp_tunnel_find(sock_net(sk), sp->pppol2tp.s_tunnel);
 
                /* Error if we can't find the tunnel */
                error = -ENOENT;
@@ -1585,19 +1751,19 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr,
        po->chan.ops     = &pppol2tp_chan_ops;
        po->chan.mtu     = session->mtu;
 
-       error = ppp_register_channel(&po->chan);
+       error = ppp_register_net_channel(sock_net(sk), &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;
 
        /* Add session to the tunnel's hash list */
-       write_lock(&tunnel->hlist_lock);
+       write_lock_bh(&tunnel->hlist_lock);
        hlist_add_head(&session->hlist,
                       pppol2tp_session_id_hash(tunnel,
                                                session->tunnel_addr.s_session));
-       write_unlock(&tunnel->hlist_lock);
+       write_unlock_bh(&tunnel->hlist_lock);
 
        atomic_inc(&pppol2tp_session_count);
 
@@ -1607,12 +1773,21 @@ out_no_ppp:
        PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO,
               "%s: created\n", session->name);
 
+end_put_tun:
+       sock_put(tunnel_sock);
 end:
        release_sock(sk);
 
-       if (error != 0)
-               PRINTK(session ? session->debug : -1, PPPOL2TP_MSG_CONTROL, KERN_WARNING,
-                      "%s: connect failed: %d\n", session->name, error);
+       if (error != 0) {
+               if (session)
+                       PRINTK(session->debug,
+                               PPPOL2TP_MSG_CONTROL, KERN_WARNING,
+                               "%s: connect failed: %d\n",
+                               session->name, error);
+               else
+                       PRINTK(-1, PPPOL2TP_MSG_CONTROL, KERN_WARNING,
+                               "connect failed: %d\n", error);
+       }
 
        return error;
 }
@@ -1647,6 +1822,7 @@ static int pppol2tp_getname(struct socket *sock, struct sockaddr *uaddr,
        *usockaddr_len = len;
 
        error = 0;
+       sock_put(sock->sk);
 
 end:
        return error;
@@ -1885,14 +2061,17 @@ static int pppol2tp_ioctl(struct socket *sock, unsigned int cmd,
                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;
 }
@@ -2004,7 +2183,7 @@ static int pppol2tp_session_setsockopt(struct sock *sk,
  * session or the special tunnel type.
  */
 static int pppol2tp_setsockopt(struct socket *sock, int level, int optname,
-                              char __user *optval, int optlen)
+                              char __user *optval, unsigned int optlen)
 {
        struct sock *sk = sock->sk;
        struct pppol2tp_session *session = sk->sk_user_data;
@@ -2038,14 +2217,17 @@ static int pppol2tp_setsockopt(struct socket *sock, int level, int optname,
                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;
 }
@@ -2054,7 +2236,7 @@ end:
  */
 static int pppol2tp_tunnel_getsockopt(struct sock *sk,
                                      struct pppol2tp_tunnel *tunnel,
-                                     int optname, int __user *val)
+                                     int optname, int *val)
 {
        int err = 0;
 
@@ -2077,7 +2259,7 @@ static int pppol2tp_tunnel_getsockopt(struct sock *sk,
  */
 static int pppol2tp_session_getsockopt(struct sock *sk,
                                       struct pppol2tp_session *session,
-                                      int optname, int __user *val)
+                                      int optname, int *val)
 {
        int err = 0;
 
@@ -2160,20 +2342,24 @@ static int pppol2tp_getsockopt(struct socket *sock, int level,
                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;
 }
@@ -2187,8 +2373,9 @@ end:
 #include <linux/seq_file.h>
 
 struct pppol2tp_seq_data {
-       struct pppol2tp_tunnel *tunnel; /* current tunnel */
-       struct pppol2tp_session *session; /* NULL means get first session in tunnel */
+       struct seq_net_private p;
+       struct pppol2tp_tunnel *tunnel;         /* current tunnel */
+       struct pppol2tp_session *session;       /* NULL means get first session in tunnel */
 };
 
 static struct pppol2tp_session *next_session(struct pppol2tp_tunnel *tunnel, struct pppol2tp_session *curr)
@@ -2199,7 +2386,7 @@ static struct pppol2tp_session *next_session(struct pppol2tp_tunnel *tunnel, str
        int next = 0;
        int i;
 
-       read_lock(&tunnel->hlist_lock);
+       read_lock_bh(&tunnel->hlist_lock);
        for (i = 0; i < PPPOL2TP_HASH_SIZE; i++) {
                hlist_for_each_entry(session, walk, &tunnel->session_hlist[i], hlist) {
                        if (curr == NULL) {
@@ -2217,24 +2404,25 @@ static struct pppol2tp_session *next_session(struct pppol2tp_tunnel *tunnel, str
                }
        }
 out:
-       read_unlock(&tunnel->hlist_lock);
+       read_unlock_bh(&tunnel->hlist_lock);
        if (!found)
                session = NULL;
 
        return session;
 }
 
-static struct pppol2tp_tunnel *next_tunnel(struct pppol2tp_tunnel *curr)
+static struct pppol2tp_tunnel *next_tunnel(struct pppol2tp_net *pn,
+                                          struct pppol2tp_tunnel *curr)
 {
        struct pppol2tp_tunnel *tunnel = NULL;
 
-       read_lock(&pppol2tp_tunnel_list_lock);
-       if (list_is_last(&curr->list, &pppol2tp_tunnel_list)) {
+       read_lock_bh(&pn->pppol2tp_tunnel_list_lock);
+       if (list_is_last(&curr->list, &pn->pppol2tp_tunnel_list)) {
                goto out;
        }
        tunnel = list_entry(curr->list.next, struct pppol2tp_tunnel, list);
 out:
-       read_unlock(&pppol2tp_tunnel_list_lock);
+       read_unlock_bh(&pn->pppol2tp_tunnel_list_lock);
 
        return tunnel;
 }
@@ -2242,6 +2430,7 @@ out:
 static void *pppol2tp_seq_start(struct seq_file *m, loff_t *offs)
 {
        struct pppol2tp_seq_data *pd = SEQ_START_TOKEN;
+       struct pppol2tp_net *pn;
        loff_t pos = *offs;
 
        if (!pos)
@@ -2249,14 +2438,15 @@ static void *pppol2tp_seq_start(struct seq_file *m, loff_t *offs)
 
        BUG_ON(m->private == NULL);
        pd = m->private;
+       pn = pppol2tp_pernet(seq_file_net(m));
 
        if (pd->tunnel == NULL) {
-               if (!list_empty(&pppol2tp_tunnel_list))
-                       pd->tunnel = list_entry(pppol2tp_tunnel_list.next, struct pppol2tp_tunnel, list);
+               if (!list_empty(&pn->pppol2tp_tunnel_list))
+                       pd->tunnel = list_entry(pn->pppol2tp_tunnel_list.next, struct pppol2tp_tunnel, list);
        } else {
                pd->session = next_session(pd->tunnel, pd->session);
                if (pd->session == NULL) {
-                       pd->tunnel = next_tunnel(pd->tunnel);
+                       pd->tunnel = next_tunnel(pn, pd->tunnel);
                }
        }
 
@@ -2289,10 +2479,12 @@ static void pppol2tp_seq_tunnel_show(struct seq_file *m, void *v)
                   atomic_read(&tunnel->ref_count) - 1);
        seq_printf(m, " %08x %llu/%llu/%llu %llu/%llu/%llu\n",
                   tunnel->debug,
-                  tunnel->stats.tx_packets, tunnel->stats.tx_bytes,
-                  tunnel->stats.tx_errors,
-                  tunnel->stats.rx_packets, tunnel->stats.rx_bytes,
-                  tunnel->stats.rx_errors);
+                  (unsigned long long)tunnel->stats.tx_packets,
+                  (unsigned long long)tunnel->stats.tx_bytes,
+                  (unsigned long long)tunnel->stats.tx_errors,
+                  (unsigned long long)tunnel->stats.rx_packets,
+                  (unsigned long long)tunnel->stats.rx_bytes,
+                  (unsigned long long)tunnel->stats.rx_errors);
 }
 
 static void pppol2tp_seq_session_show(struct seq_file *m, void *v)
@@ -2320,12 +2512,12 @@ static void pppol2tp_seq_session_show(struct seq_file *m, void *v)
                   jiffies_to_msecs(session->reorder_timeout));
        seq_printf(m, "   %hu/%hu %llu/%llu/%llu %llu/%llu/%llu\n",
                   session->nr, session->ns,
-                  session->stats.tx_packets,
-                  session->stats.tx_bytes,
-                  session->stats.tx_errors,
-                  session->stats.rx_packets,
-                  session->stats.rx_bytes,
-                  session->stats.rx_errors);
+                  (unsigned long long)session->stats.tx_packets,
+                  (unsigned long long)session->stats.tx_bytes,
+                  (unsigned long long)session->stats.tx_errors,
+                  (unsigned long long)session->stats.rx_packets,
+                  (unsigned long long)session->stats.rx_bytes,
+                  (unsigned long long)session->stats.rx_errors);
 }
 
 static int pppol2tp_seq_show(struct seq_file *m, void *v)
@@ -2355,7 +2547,7 @@ out:
        return 0;
 }
 
-static struct seq_operations pppol2tp_seq_ops = {
+static const struct seq_operations pppol2tp_seq_ops = {
        .start          = pppol2tp_seq_start,
        .next           = pppol2tp_seq_next,
        .stop           = pppol2tp_seq_stop,
@@ -2368,58 +2560,25 @@ static struct seq_operations pppol2tp_seq_ops = {
  */
 static int pppol2tp_proc_open(struct inode *inode, struct file *file)
 {
-       struct seq_file *m;
-       struct pppol2tp_seq_data *pd;
-       int ret = 0;
-
-       ret = seq_open(file, &pppol2tp_seq_ops);
-       if (ret < 0)
-               goto out;
-
-       m = file->private_data;
-
-       /* Allocate and fill our proc_data for access later */
-       ret = -ENOMEM;
-       m->private = kzalloc(sizeof(struct pppol2tp_seq_data), GFP_KERNEL);
-       if (m->private == NULL)
-               goto out;
-
-       pd = m->private;
-       ret = 0;
-
-out:
-       return ret;
-}
-
-/* Called when /proc file access completes.
- */
-static int pppol2tp_proc_release(struct inode *inode, struct file *file)
-{
-       struct seq_file *m = (struct seq_file *)file->private_data;
-
-       kfree(m->private);
-       m->private = NULL;
-
-       return seq_release(inode, file);
+       return seq_open_net(inode, file, &pppol2tp_seq_ops,
+                           sizeof(struct pppol2tp_seq_data));
 }
 
-static struct file_operations pppol2tp_proc_fops = {
+static const struct file_operations pppol2tp_proc_fops = {
        .owner          = THIS_MODULE,
        .open           = pppol2tp_proc_open,
        .read           = seq_read,
        .llseek         = seq_lseek,
-       .release        = pppol2tp_proc_release,
+       .release        = seq_release_net,
 };
 
-static struct proc_dir_entry *pppol2tp_proc;
-
 #endif /* CONFIG_PROC_FS */
 
 /*****************************************************************************
  * Init and cleanup
  *****************************************************************************/
 
-static struct proto_ops pppol2tp_ops = {
+static const struct proto_ops pppol2tp_ops = {
        .family         = AF_PPPOX,
        .owner          = THIS_MODULE,
        .release        = pppol2tp_release,
@@ -2444,6 +2603,57 @@ static struct pppox_proto pppol2tp_proto = {
        .ioctl          = pppol2tp_ioctl
 };
 
+static __net_init int pppol2tp_init_net(struct net *net)
+{
+       struct pppol2tp_net *pn;
+       struct proc_dir_entry *pde;
+       int err;
+
+       pn = kzalloc(sizeof(*pn), GFP_KERNEL);
+       if (!pn)
+               return -ENOMEM;
+
+       INIT_LIST_HEAD(&pn->pppol2tp_tunnel_list);
+       rwlock_init(&pn->pppol2tp_tunnel_list_lock);
+
+       err = net_assign_generic(net, pppol2tp_net_id, pn);
+       if (err)
+               goto out;
+
+       pde = proc_net_fops_create(net, "pppol2tp", S_IRUGO, &pppol2tp_proc_fops);
+#ifdef CONFIG_PROC_FS
+       if (!pde) {
+               err = -ENOMEM;
+               goto out;
+       }
+#endif
+
+       return 0;
+
+out:
+       kfree(pn);
+       return err;
+}
+
+static __net_exit void pppol2tp_exit_net(struct net *net)
+{
+       struct pppoe_net *pn;
+
+       proc_net_remove(net, "pppol2tp");
+       pn = net_generic(net, pppol2tp_net_id);
+       /*
+        * if someone has cached our net then
+        * further net_generic call will return NULL
+        */
+       net_assign_generic(net, pppol2tp_net_id, NULL);
+       kfree(pn);
+}
+
+static struct pernet_operations pppol2tp_net_ops = {
+       .init = pppol2tp_init_net,
+       .exit = pppol2tp_exit_net,
+};
+
 static int __init pppol2tp_init(void)
 {
        int err;
@@ -2455,20 +2665,15 @@ static int __init pppol2tp_init(void)
        if (err)
                goto out_unregister_pppol2tp_proto;
 
-#ifdef CONFIG_PROC_FS
-       pppol2tp_proc = create_proc_entry("pppol2tp", 0, proc_net);
-       if (!pppol2tp_proc) {
-               err = -ENOMEM;
+       err = register_pernet_gen_device(&pppol2tp_net_id, &pppol2tp_net_ops);
+       if (err)
                goto out_unregister_pppox_proto;
-       }
-       pppol2tp_proc->proc_fops = &pppol2tp_proc_fops;
-#endif /* CONFIG_PROC_FS */
+
        printk(KERN_INFO "PPPoL2TP kernel driver, %s\n",
               PPPOL2TP_DRV_VERSION);
 
 out:
        return err;
-
 out_unregister_pppox_proto:
        unregister_pppox_proto(PX_PROTO_OL2TP);
 out_unregister_pppol2tp_proto:
@@ -2479,17 +2684,14 @@ out_unregister_pppol2tp_proto:
 static void __exit pppol2tp_exit(void)
 {
        unregister_pppox_proto(PX_PROTO_OL2TP);
-
-#ifdef CONFIG_PROC_FS
-       remove_proc_entry("pppol2tp", proc_net);
-#endif
+       unregister_pernet_gen_device(pppol2tp_net_id, &pppol2tp_net_ops);
        proto_unregister(&pppol2tp_sk_proto);
 }
 
 module_init(pppol2tp_init);
 module_exit(pppol2tp_exit);
 
-MODULE_AUTHOR("Martijn van Oosterhout <kleptog@svana.org>,"
+MODULE_AUTHOR("Martijn van Oosterhout <kleptog@svana.org>, "
              "James Chapman <jchapman@katalix.com>");
 MODULE_DESCRIPTION("PPP over L2TP over UDP");
 MODULE_LICENSE("GPL");