aboutsummaryrefslogtreecommitdiffstats
BranchCommit messageAuthorAge
masterAdded missing tegra files.Jonathan Herman12 years
wip-mcClean this commitJonathan Herman12 years
wip-nested-lockingMerge branch 'wip-nested-locking' into tegra-nested-lockingJonathan Herman12 years
 
e'>wip-fmlp-dequeue The LITMUS^RT kernel.Bjoern Brandenburg
aboutsummaryrefslogblamecommitdiffstats
path: root/net/l2tp/l2tp_core.c
blob: bea259043205ebe3605c34ed35da504807792af1 (plain) (tree)



















                                                                       

                                           


                         
                          














                             
                     

                      
                       








                              
                            
                     
                         


                                      
                             

                          
                         













                                      
                                 










                                          


                                                       
                                   








                                                                                               
                                        




                                          
                                         
                                                               
                                           

  
                                                         
 




                                                              






                                                           













                                                                         













                                                                         




                                                                 











                                                                              



                                                                            
                                                                       


















                                                                            
                              




                  

                                                                            
                                                 








                                                             
                     
 
 







                                                                                
 
                           
                                                                       
                                                        
                                             


                                       
                             



                    













                                                                           
                                                                                                   
 
                                        
                                     
 







                                                                    
                                          
                                                            













                                                                               




                                                       
                                                                                    












                                                                    






                                                                               

                                     
                           
                                                         
                                                                                                
                                                               
                                                     




                                               
                             




                                               






                                                                    

                                                                      
                                                     
                                             


                                      
                             










                                                                  

                                                                      
                                    
                                             



                                      
                             















                                                                                  
                                      




                                                                           



                                                                                        
                                                                        





















                                                                                    



                                                          



                                        
                                               
 

                                                                          























                                                                             
      


                                                                     

                                                                         




                                                                                                                 
                                                  







                                                               
                                                    



                                                                                  


                                                                   
                                                                  




                                                                                                             









                                                                      
                           





                                                 











                                                                         




                                                                                










                                                                                




                                                                  









                                                                                
                















                                                                                             










                                                                                                       
    





                 


























































                                                                      
   


                                                                            
 
                                                     
                   
                   








                                                                      


                                                                                      



                                                                               
                                                                            




                                                








                                                                      





                                                    
 


                                                        
 


                                                                               










                                                                         


                                                                        
                 

         


                                                         





                                                                             


                                                                                 
                                               
                                                                              





                                                                              


                                                                                                  
                                                                         








                                                                             


                                                                                  
                                              
                                                                              
                                               


                                                                                                  
                                                                         



                                     












                                                                      

























                                                                                 

                                                     












                                                                      
               

        
                                                   





                                           


                                
















                                                           





                                                                               

                                                                              




                                            


                    
                                      





                                                     


                                                             


                           





                                                

                                                                                

         


                                  





                                               


                                                                                     







                                                                    


                                                             
























                                                                          
                                             
                                                               


                                                                        



                                                                                  


                 





                                               














                                                             

                                                                  



















                                                                         
                                                                            
 
                                                     
                           
                           














                                                  
                                      

                                                                         
         

                           

 
                                                                            
 
                                                     

                          
 










                                                                     












                                                                          


                                                                     







                                                        
 
                           
 
 
                                                                            
                                                            






                                                     

                                                                               
            

                                                                        

                                             

                                                                                              
 


                                                                            


                                               
                           
                           
                                                                     
                                                                

            
                                                             


                          



                                                               
                

                                                           



                 
 





                                                                                 

                                                     
                         
                          
                               
                     

                                                                                      
                                   





                                                                      
                                
                                          

                                     
         
 
                               
                                                                 
 
                                       




                                                                               

                                     

                                    


                                

                                                     
                                                           
 

                            


                                      






                                                     

                                                                   
                           
                                                                   


                                                                 

                    

                                                                       



                               

         
                                                   

                           
 
                   










                                                                               
                                                 
 
                                                     
                            
 


                           
                                                                              
 
 
                                       




                                                                           
                                                   



                               

                                             

                                                  
                            
 





                                                           
 
                                     

                                         


                                          


               


                                                                       
                                                     







                                     

                                                                            






                                                                                

                                                                          


                                                        




                                                             
                                                       

                                                          





                                                                   

                                                           











                                                                      
                                        
 









                                                             


                                                                      
                                                        
 

                                                     
                                                                           
                               
 
 












                                                                  
 



                                                                              

                                                                      
           


                                               
                


                                                              
         

                                 
 
 


                                                               




                                                                      
   




                                                            

                          


                                             
                           

                                               
      


                                

                                                      
                                                                               

                                         
 
                                                     
 







                                                                               
 








                                                                            




                                                                     


                      
                                                                              


                                         
                                                     
 
















                                                                              

                                            
                                                     



                               

                                                      

                                                                    

                                         
 
                                                     
 







                                                                              
 











                                                                           

                                                                   

                                         
 
                                                     
 















                                                                                






                         
                      
                                

                                                      





                              

                                               






                                                                                                                                                          
                                                        

                                                                 

                                                                
           
                     

                                                                             


                                 

                                               
                                                                             
                                                   







                                                                       

                                 



                      


                                   
                                 



                                                     
                                                                                       






                                                                            
                                                                                       



                                                                             


                                                           
                                 





                                                          


















                                                                 
                        

                                           




                                                     
                                                           



                                                                  

                                                                                





                                                 
                                                                        




                                                                                
                                                                   
                           
                                                                   


                                             
                                   
         








                                                                      
                        

                                                                                        

                                       


                                                           

                                      


                                                                  
                                                                           

                                         


                                                           





                                  



                                                                   





                                      



                                                              
                                     
                                                                 


                                      



                                                    
                                                     


                                                      
                     
                                                           







                                                        










                                                                             
 


                                                     



                                                     
                                                                               

                                                                            



                                                                     
                 
         
 
                                         
 




                                                                     


                                         
                                          

                                                   
                           
                                           
                                           



                                       


                                                            
                                                                           





                                              


                                                                                                       


         
                                               
 










                                                                                                                                                      
                                




                                                              



                                                     






                                                                
                                                        




                                                       
                                                       
                                                    




                                                          







                                                                                                     

                 






                                                                         














                                                                           



                                                                            



                                                                                   

                 














                                                                               
                                                            
                 
 
                                              
                                                   
 


                                                               
                                                     
 
                 

 











                                                                      

                                                
                              











                                                   
                                                         





                                                   
                                                            







                                                



                                           









                                                      
/*
 * L2TP core.
 *
 * Copyright (c) 2008,2009,2010 Katalix Systems Ltd
 *
 * This file contains some code of the original L2TPv2 pppol2tp
 * driver, which has the following copyright:
 *
 * Authors:	Martijn van Oosterhout <kleptog@svana.org>
 *		James Chapman (jchapman@katalix.com)
 * Contributors:
 *		Michal Ostrowski <mostrows@speakeasy.net>
 *		Arnaldo Carvalho de Melo <acme@xconectiva.com.br>
 *		David S. Miller (davem@redhat.com)
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 */

#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt

#include <linux/module.h>
#include <linux/string.h>
#include <linux/list.h>
#include <linux/rculist.h>
#include <linux/uaccess.h>

#include <linux/kernel.h>
#include <linux/spinlock.h>
#include <linux/kthread.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/jiffies.h>

#include <linux/netdevice.h>
#include <linux/net.h>
#include <linux/inetdevice.h>
#include <linux/skbuff.h>
#include <linux/init.h>
#include <linux/in.h>
#include <linux/ip.h>
#include <linux/udp.h>
#include <linux/l2tp.h>
#include <linux/hash.h>
#include <linux/sort.h>
#include <linux/file.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>
#include <net/inet_common.h>
#include <net/xfrm.h>
#include <net/protocol.h>
#include <net/inet6_connection_sock.h>
#include <net/inet_ecn.h>
#include <net/ip6_route.h>
#include <net/ip6_checksum.h>

#include <asm/byteorder.h>
#include <linux/atomic.h>

#include "l2tp_core.h"

#define L2TP_DRV_VERSION	"V2.0"

/* L2TP header constants */
#define L2TP_HDRFLAG_T	   0x8000
#define L2TP_HDRFLAG_L	   0x4000
#define L2TP_HDRFLAG_S	   0x0800
#define L2TP_HDRFLAG_O	   0x0200
#define L2TP_HDRFLAG_P	   0x0100

#define L2TP_HDR_VER_MASK  0x000F
#define L2TP_HDR_VER_2	   0x0002
#define L2TP_HDR_VER_3	   0x0003

/* L2TPv3 default L2-specific sublayer */
#define L2TP_SLFLAG_S	   0x40000000
#define L2TP_SL_SEQ_MASK   0x00ffffff

#define L2TP_HDR_SIZE_SEQ		10
#define L2TP_HDR_SIZE_NOSEQ		6

/* Default trace flags */
#define L2TP_DEFAULT_DEBUG_FLAGS	0

/* Private data stored for received packets in the skb.
 */
struct l2tp_skb_cb {
	u32			ns;
	u16			has_seq;
	u16			length;
	unsigned long		expires;
};

#define L2TP_SKB_CB(skb)	((struct l2tp_skb_cb *) &skb->cb[sizeof(struct inet_skb_parm)])

static atomic_t l2tp_tunnel_count;
static atomic_t l2tp_session_count;
static struct workqueue_struct *l2tp_wq;

/* per-net private data for this module */
static unsigned int l2tp_net_id;
struct l2tp_net {
	struct list_head l2tp_tunnel_list;
	spinlock_t l2tp_tunnel_list_lock;
	struct hlist_head l2tp_session_hlist[L2TP_HASH_SIZE_2];
	spinlock_t l2tp_session_hlist_lock;
};

static void l2tp_tunnel_free(struct l2tp_tunnel *tunnel);

static inline struct l2tp_tunnel *l2tp_tunnel(struct sock *sk)
{
	return sk->sk_user_data;
}

static inline struct l2tp_net *l2tp_pernet(struct net *net)
{
	BUG_ON(!net);

	return net_generic(net, l2tp_net_id);
}

/* Tunnel reference counts. Incremented per session that is added to
 * the tunnel.
 */
static inline void l2tp_tunnel_inc_refcount_1(struct l2tp_tunnel *tunnel)
{
	atomic_inc(&tunnel->ref_count);
}

static inline void l2tp_tunnel_dec_refcount_1(struct l2tp_tunnel *tunnel)
{
	if (atomic_dec_and_test(&tunnel->ref_count))
		l2tp_tunnel_free(tunnel);
}
#ifdef L2TP_REFCNT_DEBUG
#define l2tp_tunnel_inc_refcount(_t)					\
do {									\
	pr_debug("l2tp_tunnel_inc_refcount: %s:%d %s: cnt=%d\n",	\
		 __func__, __LINE__, (_t)->name,			\
		 atomic_read(&_t->ref_count));				\
	l2tp_tunnel_inc_refcount_1(_t);					\
} while (0)
#define l2tp_tunnel_dec_refcount(_t)
do {									\
	pr_debug("l2tp_tunnel_dec_refcount: %s:%d %s: cnt=%d\n",	\
		 __func__, __LINE__, (_t)->name,			\
		 atomic_read(&_t->ref_count));				\
	l2tp_tunnel_dec_refcount_1(_t);					\
} while (0)
#else
#define l2tp_tunnel_inc_refcount(t) l2tp_tunnel_inc_refcount_1(t)
#define l2tp_tunnel_dec_refcount(t) l2tp_tunnel_dec_refcount_1(t)
#endif

/* Session hash global list for L2TPv3.
 * The session_id SHOULD be random according to RFC3931, but several
 * L2TP implementations use incrementing session_ids.  So we do a real
 * hash on the session_id, rather than a simple bitmask.
 */
static inline struct hlist_head *
l2tp_session_id_hash_2(struct l2tp_net *pn, u32 session_id)
{
	return &pn->l2tp_session_hlist[hash_32(session_id, L2TP_HASH_BITS_2)];

}

/* Lookup the tunnel socket, possibly involving the fs code if the socket is
 * owned by userspace.  A struct sock returned from this function must be
 * released using l2tp_tunnel_sock_put once you're done with it.
 */
static struct sock *l2tp_tunnel_sock_lookup(struct l2tp_tunnel *tunnel)
{
	int err = 0;
	struct socket *sock = NULL;
	struct sock *sk = NULL;

	if (!tunnel)
		goto out;

	if (tunnel->fd >= 0) {
		/* Socket is owned by userspace, who might be in the process
		 * of closing it.  Look the socket up using the fd to ensure
		 * consistency.
		 */
		sock = sockfd_lookup(tunnel->fd, &err);
		if (sock)
			sk = sock->sk;
	} else {
		/* Socket is owned by kernelspace */
		sk = tunnel->sock;
		sock_hold(sk);
	}

out:
	return sk;
}

/* Drop a reference to a tunnel socket obtained via. l2tp_tunnel_sock_put */
static void l2tp_tunnel_sock_put(struct sock *sk)
{
	struct l2tp_tunnel *tunnel = l2tp_sock_to_tunnel(sk);
	if (tunnel) {
		if (tunnel->fd >= 0) {
			/* Socket is owned by userspace */
			sockfd_put(sk->sk_socket);
		}
		sock_put(sk);
	}
	sock_put(sk);
}

/* Lookup a session by id in the global session list
 */
static struct l2tp_session *l2tp_session_find_2(struct net *net, u32 session_id)
{
	struct l2tp_net *pn = l2tp_pernet(net);
	struct hlist_head *session_list =
		l2tp_session_id_hash_2(pn, session_id);
	struct l2tp_session *session;

	rcu_read_lock_bh();
	hlist_for_each_entry_rcu(session, session_list, global_hlist) {
		if (session->session_id == session_id) {
			rcu_read_unlock_bh();
			return session;
		}
	}
	rcu_read_unlock_bh();

	return NULL;
}

/* Session hash list.
 * The session_id SHOULD be random according to RFC2661, but several
 * L2TP implementations (Cisco and Microsoft) use incrementing
 * session_ids.  So we do a real hash on the session_id, rather than a
 * simple bitmask.
 */
static inline struct hlist_head *
l2tp_session_id_hash(struct l2tp_tunnel *tunnel, u32 session_id)
{
	return &tunnel->session_hlist[hash_32(session_id, L2TP_HASH_BITS)];
}

/* Lookup a session by id
 */
struct l2tp_session *l2tp_session_find(struct net *net, struct l2tp_tunnel *tunnel, u32 session_id)
{
	struct hlist_head *session_list;
	struct l2tp_session *session;

	/* In L2TPv3, session_ids are unique over all tunnels and we
	 * sometimes need to look them up before we know the
	 * tunnel.
	 */
	if (tunnel == NULL)
		return l2tp_session_find_2(net, session_id);

	session_list = l2tp_session_id_hash(tunnel, session_id);
	read_lock_bh(&tunnel->hlist_lock);
	hlist_for_each_entry(session, session_list, hlist) {
		if (session->session_id == session_id) {
			read_unlock_bh(&tunnel->hlist_lock);
			return session;
		}
	}
	read_unlock_bh(&tunnel->hlist_lock);

	return NULL;
}
EXPORT_SYMBOL_GPL(l2tp_session_find);