2010-04-02 10:18:33 +04:00
/*
* L2TP internal definitions .
*
* Copyright ( c ) 2008 , 2009 Katalix Systems Ltd
*
* 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 .
*/
# ifndef _L2TP_CORE_H_
# define _L2TP_CORE_H_
/* Just some random numbers */
# define L2TP_TUNNEL_MAGIC 0x42114DDA
# define L2TP_SESSION_MAGIC 0x0C04EB7D
2010-04-02 10:18:49 +04:00
/* Per tunnel, session hash table size */
2010-04-02 10:18:33 +04:00
# define L2TP_HASH_BITS 4
# define L2TP_HASH_SIZE (1 << L2TP_HASH_BITS)
2010-04-02 10:18:49 +04:00
/* System-wide, session hash table size */
# define L2TP_HASH_BITS_2 8
# define L2TP_HASH_SIZE_2 (1 << L2TP_HASH_BITS_2)
2010-04-02 10:18:33 +04:00
/* Debug message categories for the DEBUG socket option */
enum {
L2TP_MSG_DEBUG = ( 1 < < 0 ) , /* verbose debug (if
* compiled in ) */
L2TP_MSG_CONTROL = ( 1 < < 1 ) , /* userspace - kernel
* interface */
L2TP_MSG_SEQ = ( 1 < < 2 ) , /* sequence numbers */
L2TP_MSG_DATA = ( 1 < < 3 ) , /* data packets */
} ;
2010-04-02 10:18:49 +04:00
enum l2tp_pwtype {
L2TP_PWTYPE_NONE = 0x0000 ,
L2TP_PWTYPE_ETH_VLAN = 0x0004 ,
L2TP_PWTYPE_ETH = 0x0005 ,
L2TP_PWTYPE_PPP = 0x0007 ,
L2TP_PWTYPE_PPP_AC = 0x0008 ,
L2TP_PWTYPE_IP = 0x000b ,
__L2TP_PWTYPE_MAX
} ;
enum l2tp_l2spec_type {
L2TP_L2SPECTYPE_NONE ,
L2TP_L2SPECTYPE_DEFAULT ,
} ;
2010-04-02 10:19:00 +04:00
enum l2tp_encap_type {
L2TP_ENCAPTYPE_UDP ,
L2TP_ENCAPTYPE_IP ,
} ;
2010-04-02 10:18:33 +04:00
struct sk_buff ;
struct l2tp_stats {
u64 tx_packets ;
u64 tx_bytes ;
u64 tx_errors ;
u64 rx_packets ;
u64 rx_bytes ;
u64 rx_seq_discards ;
u64 rx_oos_packets ;
u64 rx_errors ;
2010-04-02 10:18:49 +04:00
u64 rx_cookie_discards ;
2010-04-02 10:18:33 +04:00
} ;
struct l2tp_tunnel ;
/* Describes a session. Contains information to determine incoming
* packets and transmit outgoing ones .
*/
struct l2tp_session_cfg {
2010-04-02 10:18:49 +04:00
enum l2tp_pwtype pw_type ;
2010-04-02 10:18:33 +04:00
unsigned data_seq : 2 ; /* data sequencing level
* 0 = > none , 1 = > IP only ,
* 2 = > all
*/
unsigned recv_seq : 1 ; /* expect receive packets with
* sequence numbers ? */
unsigned send_seq : 1 ; /* send packets with sequence
* numbers ? */
unsigned lns_mode : 1 ; /* behave as LNS? LAC enables
* sequence numbers under
* control of LNS . */
int debug ; /* bitmask of debug message
* categories */
2010-04-02 10:18:49 +04:00
u16 offset ; /* offset to payload */
u16 l2specific_len ; /* Layer 2 specific length */
u16 l2specific_type ; /* Layer 2 specific type */
u8 cookie [ 8 ] ; /* optional cookie */
int cookie_len ; /* 0, 4 or 8 bytes */
u8 peer_cookie [ 8 ] ; /* peer's cookie */
int peer_cookie_len ; /* 0, 4 or 8 bytes */
2010-04-02 10:18:33 +04:00
int reorder_timeout ; /* configured reorder timeout
* ( in jiffies ) */
int mtu ;
int mru ;
} ;
struct l2tp_session {
int magic ; /* should be
* L2TP_SESSION_MAGIC */
struct l2tp_tunnel * tunnel ; /* back pointer to tunnel
* context */
u32 session_id ;
u32 peer_session_id ;
2010-04-02 10:18:49 +04:00
u8 cookie [ 8 ] ;
int cookie_len ;
u8 peer_cookie [ 8 ] ;
int peer_cookie_len ;
u16 offset ; /* offset from end of L2TP header
to beginning of data */
u16 l2specific_len ;
u16 l2specific_type ;
u16 hdr_len ;
u32 nr ; /* session NR state (receive) */
u32 ns ; /* session NR state (send) */
2010-04-02 10:18:33 +04:00
struct sk_buff_head reorder_q ; /* receive reorder queue */
struct hlist_node hlist ; /* Hash list node */
atomic_t ref_count ;
char name [ 32 ] ; /* for logging */
unsigned data_seq : 2 ; /* data sequencing level
* 0 = > none , 1 = > IP only ,
* 2 = > all
*/
unsigned recv_seq : 1 ; /* expect receive packets with
* sequence numbers ? */
unsigned send_seq : 1 ; /* send packets with sequence
* numbers ? */
unsigned lns_mode : 1 ; /* behave as LNS? LAC enables
* sequence numbers under
* control of LNS . */
int debug ; /* bitmask of debug message
* categories */
int reorder_timeout ; /* configured reorder timeout
* ( in jiffies ) */
int mtu ;
int mru ;
2010-04-02 10:18:49 +04:00
enum l2tp_pwtype pwtype ;
2010-04-02 10:18:33 +04:00
struct l2tp_stats stats ;
2010-04-02 10:18:49 +04:00
struct hlist_node global_hlist ; /* Global hash list node */
2010-04-02 10:18:33 +04:00
2010-04-02 10:18:49 +04:00
int ( * build_header ) ( struct l2tp_session * session , void * buf ) ;
2010-04-02 10:18:33 +04:00
void ( * recv_skb ) ( struct l2tp_session * session , struct sk_buff * skb , int data_len ) ;
void ( * session_close ) ( struct l2tp_session * session ) ;
void ( * ref ) ( struct l2tp_session * session ) ;
void ( * deref ) ( struct l2tp_session * session ) ;
uint8_t priv [ 0 ] ; /* private data */
} ;
/* Describes the tunnel. It contains info to track all the associated
* sessions so incoming packets can be sorted out
*/
struct l2tp_tunnel_cfg {
int debug ; /* bitmask of debug message
* categories */
2010-04-02 10:19:00 +04:00
enum l2tp_encap_type encap ;
2010-04-02 10:18:33 +04:00
} ;
struct l2tp_tunnel {
int magic ; /* Should be L2TP_TUNNEL_MAGIC */
rwlock_t hlist_lock ; /* protect session_hlist */
struct hlist_head session_hlist [ L2TP_HASH_SIZE ] ;
/* hashed list of sessions,
* hashed by id */
u32 tunnel_id ;
u32 peer_tunnel_id ;
int version ; /* 2=>L2TPv2, 3=>L2TPv3 */
char name [ 20 ] ; /* for logging */
int debug ; /* bitmask of debug message
* categories */
2010-04-02 10:19:00 +04:00
enum l2tp_encap_type encap ;
2010-04-02 10:18:33 +04:00
struct l2tp_stats stats ;
struct list_head list ; /* Keep a list of all tunnels */
struct net * l2tp_net ; /* the net we belong to */
atomic_t ref_count ;
int ( * recv_payload_hook ) ( struct sk_buff * skb ) ;
void ( * old_sk_destruct ) ( struct sock * ) ;
struct sock * sock ; /* Parent socket */
int fd ;
uint8_t priv [ 0 ] ; /* private data */
} ;
static inline void * l2tp_tunnel_priv ( struct l2tp_tunnel * tunnel )
{
return & tunnel - > priv [ 0 ] ;
}
static inline void * l2tp_session_priv ( struct l2tp_session * session )
{
return & session - > priv [ 0 ] ;
}
static inline struct l2tp_tunnel * l2tp_sock_to_tunnel ( struct sock * sk )
{
struct l2tp_tunnel * tunnel ;
if ( sk = = NULL )
return NULL ;
sock_hold ( sk ) ;
tunnel = ( struct l2tp_tunnel * ) ( sk - > sk_user_data ) ;
if ( tunnel = = NULL ) {
sock_put ( sk ) ;
goto out ;
}
BUG_ON ( tunnel - > magic ! = L2TP_TUNNEL_MAGIC ) ;
out :
return tunnel ;
}
2010-04-02 10:18:49 +04:00
extern struct l2tp_session * l2tp_session_find ( struct net * net , struct l2tp_tunnel * tunnel , u32 session_id ) ;
2010-04-02 10:18:33 +04:00
extern struct l2tp_session * l2tp_session_find_nth ( struct l2tp_tunnel * tunnel , int nth ) ;
extern struct l2tp_tunnel * l2tp_tunnel_find ( struct net * net , u32 tunnel_id ) ;
extern struct l2tp_tunnel * l2tp_tunnel_find_nth ( struct net * net , int nth ) ;
extern int l2tp_tunnel_create ( struct net * net , int fd , int version , u32 tunnel_id , u32 peer_tunnel_id , struct l2tp_tunnel_cfg * cfg , struct l2tp_tunnel * * tunnelp ) ;
extern struct l2tp_session * l2tp_session_create ( int priv_size , struct l2tp_tunnel * tunnel , u32 session_id , u32 peer_session_id , struct l2tp_session_cfg * cfg ) ;
extern void l2tp_tunnel_free ( struct l2tp_tunnel * tunnel ) ;
extern void l2tp_session_free ( struct l2tp_session * session ) ;
2010-04-02 10:18:49 +04:00
extern void l2tp_recv_common ( struct l2tp_session * session , struct sk_buff * skb , unsigned char * ptr , unsigned char * optr , u16 hdrflags , int length , int ( * payload_hook ) ( struct sk_buff * skb ) ) ;
2010-04-02 10:18:33 +04:00
extern int l2tp_udp_recv_core ( struct l2tp_tunnel * tunnel , struct sk_buff * skb , int ( * payload_hook ) ( struct sk_buff * skb ) ) ;
extern int l2tp_udp_encap_recv ( struct sock * sk , struct sk_buff * skb ) ;
extern int l2tp_xmit_core ( struct l2tp_session * session , struct sk_buff * skb , size_t data_len ) ;
extern int l2tp_xmit_skb ( struct l2tp_session * session , struct sk_buff * skb , int hdr_len ) ;
extern void l2tp_tunnel_destruct ( struct sock * sk ) ;
extern void l2tp_tunnel_closeall ( struct l2tp_tunnel * tunnel ) ;
2010-04-02 10:18:49 +04:00
extern void l2tp_session_set_header_len ( struct l2tp_session * session , int version ) ;
2010-04-02 10:18:33 +04:00
/* 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 { \
printk ( KERN_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 { \
printk ( KERN_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 reference counts. Incremented when code obtains a reference
* to a session .
*/
static inline void l2tp_session_inc_refcount_1 ( struct l2tp_session * session )
{
atomic_inc ( & session - > ref_count ) ;
}
static inline void l2tp_session_dec_refcount_1 ( struct l2tp_session * session )
{
if ( atomic_dec_and_test ( & session - > ref_count ) )
l2tp_session_free ( session ) ;
}
# ifdef L2TP_REFCNT_DEBUG
# define l2tp_session_inc_refcount(_s) do { \
printk ( KERN_DEBUG " l2tp_session_inc_refcount: %s:%d %s: cnt=%d \n " , __func__ , __LINE__ , ( _s ) - > name , atomic_read ( & _s - > ref_count ) ) ; \
l2tp_session_inc_refcount_1 ( _s ) ; \
} while ( 0 )
# define l2tp_session_dec_refcount(_s) do { \
printk ( KERN_DEBUG " l2tp_session_dec_refcount: %s:%d %s: cnt=%d \n " , __func__ , __LINE__ , ( _s ) - > name , atomic_read ( & _s - > ref_count ) ) ; \
l2tp_session_dec_refcount_1 ( _s ) ; \
} while ( 0 )
# else
# define l2tp_session_inc_refcount(s) l2tp_session_inc_refcount_1(s)
# define l2tp_session_dec_refcount(s) l2tp_session_dec_refcount_1(s)
# endif
# endif /* _L2TP_CORE_H_ */