2005-04-17 02:20:36 +04:00
/*
* llc_core . c - Minimum needed routines for sap handling and module init / exit
*
* Copyright ( c ) 1997 by Procom Technology , Inc .
* 2001 - 2003 by Arnaldo Carvalho de Melo < acme @ conectiva . com . br >
*
* This program can be redistributed or modified under the terms of the
* GNU General Public License as published by the Free Software Foundation .
* This program is distributed without any warranty or implied warranty
* of merchantability or fitness for a particular purpose .
*
* See the GNU General Public License for more details .
*/
# include <linux/module.h>
# include <linux/interrupt.h>
# include <linux/if_ether.h>
# include <linux/netdevice.h>
# include <linux/slab.h>
# include <linux/string.h>
# include <linux/init.h>
2007-09-17 22:56:21 +04:00
# include <net/net_namespace.h>
2005-04-17 02:20:36 +04:00
# include <net/llc.h>
LIST_HEAD ( llc_sap_list ) ;
2014-01-03 21:19:51 +04:00
static DEFINE_SPINLOCK ( llc_sap_list_lock ) ;
2005-04-17 02:20:36 +04:00
/**
* llc_sap_alloc - allocates and initializes sap .
*
* Allocates and initializes sap .
*/
static struct llc_sap * llc_sap_alloc ( void )
{
2006-07-22 01:51:30 +04:00
struct llc_sap * sap = kzalloc ( sizeof ( * sap ) , GFP_ATOMIC ) ;
2009-12-26 14:51:05 +03:00
int i ;
2005-04-17 02:20:36 +04:00
if ( sap ) {
2008-03-29 02:28:36 +03:00
/* sap->laddr.mac - leave as a null, it's filled by bind */
2005-04-17 02:20:36 +04:00
sap - > state = LLC_SAP_STATE_ACTIVE ;
2009-12-26 14:51:02 +03:00
spin_lock_init ( & sap - > sk_lock ) ;
2009-12-26 14:51:05 +03:00
for ( i = 0 ; i < LLC_SK_LADDR_HASH_ENTRIES ; i + + )
INIT_HLIST_NULLS_HEAD ( & sap - > sk_laddr_hash [ i ] , i ) ;
2017-07-04 15:52:56 +03:00
refcount_set ( & sap - > refcnt , 1 ) ;
2005-04-17 02:20:36 +04:00
}
return sap ;
}
2005-09-22 12:14:33 +04:00
static struct llc_sap * __llc_sap_find ( unsigned char sap_value )
2005-09-22 11:43:05 +04:00
{
2013-12-20 07:14:59 +04:00
struct llc_sap * sap ;
2005-09-22 11:43:05 +04:00
list_for_each_entry ( sap , & llc_sap_list , node )
if ( sap - > laddr . lsap = = sap_value )
goto out ;
sap = NULL ;
out :
return sap ;
}
2005-04-17 02:20:36 +04:00
/**
2021-03-27 02:12:44 +03:00
* llc_sap_find - searches a SAP in station
2005-04-17 02:20:36 +04:00
* @ sap_value : sap to be found
*
2021-03-27 02:12:44 +03:00
* Searches for a sap in the sap list of the LLC ' s station upon the sap ID .
2005-09-22 11:43:05 +04:00
* If the sap is found it will be refcounted and the user will have to do
* a llc_sap_put after use .
2005-04-17 02:20:36 +04:00
* Returns the sap or % NULL if not found .
*/
struct llc_sap * llc_sap_find ( unsigned char sap_value )
{
2009-12-26 14:51:06 +03:00
struct llc_sap * sap ;
2005-04-17 02:20:36 +04:00
2009-12-26 14:51:06 +03:00
rcu_read_lock_bh ( ) ;
2005-09-22 11:43:05 +04:00
sap = __llc_sap_find ( sap_value ) ;
2018-08-07 22:41:38 +03:00
if ( ! sap | | ! llc_sap_hold_safe ( sap ) )
sap = NULL ;
2009-12-26 14:51:06 +03:00
rcu_read_unlock_bh ( ) ;
2005-04-17 02:20:36 +04:00
return sap ;
}
/**
* llc_sap_open - open interface to the upper layers .
* @ lsap : SAP number .
* @ func : rcv func for datalink protos
*
* Interface function to upper layer . Each one who wants to get a SAP
* ( for example NetBEUI ) should call this function . Returns the opened
* SAP for success , NULL for failure .
*/
struct llc_sap * llc_sap_open ( unsigned char lsap ,
int ( * func ) ( struct sk_buff * skb ,
struct net_device * dev ,
2005-08-10 06:34:12 +04:00
struct packet_type * pt ,
struct net_device * orig_dev ) )
2005-04-17 02:20:36 +04:00
{
2005-09-22 11:43:05 +04:00
struct llc_sap * sap = NULL ;
2005-04-17 02:20:36 +04:00
2009-12-26 14:51:06 +03:00
spin_lock_bh ( & llc_sap_list_lock ) ;
2005-09-22 11:43:05 +04:00
if ( __llc_sap_find ( lsap ) ) /* SAP already exists */
2005-04-17 02:20:36 +04:00
goto out ;
sap = llc_sap_alloc ( ) ;
if ( ! sap )
goto out ;
sap - > laddr . lsap = lsap ;
sap - > rcv_func = func ;
2009-12-26 14:51:06 +03:00
list_add_tail_rcu ( & sap - > node , & llc_sap_list ) ;
2005-04-17 02:20:36 +04:00
out :
2009-12-26 14:51:06 +03:00
spin_unlock_bh ( & llc_sap_list_lock ) ;
2005-04-17 02:20:36 +04:00
return sap ;
}
/**
* llc_sap_close - close interface for upper layers .
* @ sap : SAP to be closed .
*
* Close interface function to upper layer . Each one who wants to
* close an open SAP ( for example NetBEUI ) should call this function .
* Removes this sap from the list of saps in the station and then
* frees the memory for this sap .
*/
void llc_sap_close ( struct llc_sap * sap )
{
2009-12-26 14:51:05 +03:00
WARN_ON ( sap - > sk_count ) ;
2009-12-26 14:51:06 +03:00
spin_lock_bh ( & llc_sap_list_lock ) ;
list_del_rcu ( & sap - > node ) ;
spin_unlock_bh ( & llc_sap_list_lock ) ;
2018-09-11 21:42:06 +03:00
kfree_rcu ( sap , rcu ) ;
2005-04-17 02:20:36 +04:00
}
2009-03-09 11:18:29 +03:00
static struct packet_type llc_packet_type __read_mostly = {
2009-02-01 11:45:17 +03:00
. type = cpu_to_be16 ( ETH_P_802_2 ) ,
2005-04-17 02:20:36 +04:00
. func = llc_rcv ,
} ;
2009-03-09 11:18:29 +03:00
static struct packet_type llc_tr_packet_type __read_mostly = {
2009-02-01 11:45:17 +03:00
. type = cpu_to_be16 ( ETH_P_TR_802_2 ) ,
2005-04-17 02:20:36 +04:00
. func = llc_rcv ,
} ;
static int __init llc_init ( void )
{
dev_add_pack ( & llc_packet_type ) ;
dev_add_pack ( & llc_tr_packet_type ) ;
return 0 ;
}
static void __exit llc_exit ( void )
{
dev_remove_pack ( & llc_packet_type ) ;
dev_remove_pack ( & llc_tr_packet_type ) ;
}
module_init ( llc_init ) ;
module_exit ( llc_exit ) ;
EXPORT_SYMBOL ( llc_sap_list ) ;
EXPORT_SYMBOL ( llc_sap_find ) ;
EXPORT_SYMBOL ( llc_sap_open ) ;
EXPORT_SYMBOL ( llc_sap_close ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_AUTHOR ( " Procom 1997, Jay Schullist 2001, Arnaldo C. Melo 2001-2003 " ) ;
MODULE_DESCRIPTION ( " LLC IEEE 802.2 core support " ) ;