1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * llc_core.c - Minimum needed routines for sap handling and module init/exit
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * Copyright (c) 1997 by Procom Technology, Inc.
5*4882a593Smuzhiyun * 2001-2003 by Arnaldo Carvalho de Melo <acme@conectiva.com.br>
6*4882a593Smuzhiyun *
7*4882a593Smuzhiyun * This program can be redistributed or modified under the terms of the
8*4882a593Smuzhiyun * GNU General Public License as published by the Free Software Foundation.
9*4882a593Smuzhiyun * This program is distributed without any warranty or implied warranty
10*4882a593Smuzhiyun * of merchantability or fitness for a particular purpose.
11*4882a593Smuzhiyun *
12*4882a593Smuzhiyun * See the GNU General Public License for more details.
13*4882a593Smuzhiyun */
14*4882a593Smuzhiyun
15*4882a593Smuzhiyun #include <linux/module.h>
16*4882a593Smuzhiyun #include <linux/interrupt.h>
17*4882a593Smuzhiyun #include <linux/if_ether.h>
18*4882a593Smuzhiyun #include <linux/netdevice.h>
19*4882a593Smuzhiyun #include <linux/slab.h>
20*4882a593Smuzhiyun #include <linux/string.h>
21*4882a593Smuzhiyun #include <linux/init.h>
22*4882a593Smuzhiyun #include <net/net_namespace.h>
23*4882a593Smuzhiyun #include <net/llc.h>
24*4882a593Smuzhiyun
25*4882a593Smuzhiyun LIST_HEAD(llc_sap_list);
26*4882a593Smuzhiyun static DEFINE_SPINLOCK(llc_sap_list_lock);
27*4882a593Smuzhiyun
28*4882a593Smuzhiyun /**
29*4882a593Smuzhiyun * llc_sap_alloc - allocates and initializes sap.
30*4882a593Smuzhiyun *
31*4882a593Smuzhiyun * Allocates and initializes sap.
32*4882a593Smuzhiyun */
llc_sap_alloc(void)33*4882a593Smuzhiyun static struct llc_sap *llc_sap_alloc(void)
34*4882a593Smuzhiyun {
35*4882a593Smuzhiyun struct llc_sap *sap = kzalloc(sizeof(*sap), GFP_ATOMIC);
36*4882a593Smuzhiyun int i;
37*4882a593Smuzhiyun
38*4882a593Smuzhiyun if (sap) {
39*4882a593Smuzhiyun /* sap->laddr.mac - leave as a null, it's filled by bind */
40*4882a593Smuzhiyun sap->state = LLC_SAP_STATE_ACTIVE;
41*4882a593Smuzhiyun spin_lock_init(&sap->sk_lock);
42*4882a593Smuzhiyun for (i = 0; i < LLC_SK_LADDR_HASH_ENTRIES; i++)
43*4882a593Smuzhiyun INIT_HLIST_NULLS_HEAD(&sap->sk_laddr_hash[i], i);
44*4882a593Smuzhiyun refcount_set(&sap->refcnt, 1);
45*4882a593Smuzhiyun }
46*4882a593Smuzhiyun return sap;
47*4882a593Smuzhiyun }
48*4882a593Smuzhiyun
__llc_sap_find(unsigned char sap_value)49*4882a593Smuzhiyun static struct llc_sap *__llc_sap_find(unsigned char sap_value)
50*4882a593Smuzhiyun {
51*4882a593Smuzhiyun struct llc_sap *sap;
52*4882a593Smuzhiyun
53*4882a593Smuzhiyun list_for_each_entry(sap, &llc_sap_list, node)
54*4882a593Smuzhiyun if (sap->laddr.lsap == sap_value)
55*4882a593Smuzhiyun goto out;
56*4882a593Smuzhiyun sap = NULL;
57*4882a593Smuzhiyun out:
58*4882a593Smuzhiyun return sap;
59*4882a593Smuzhiyun }
60*4882a593Smuzhiyun
61*4882a593Smuzhiyun /**
62*4882a593Smuzhiyun * llc_sap_find - searchs a SAP in station
63*4882a593Smuzhiyun * @sap_value: sap to be found
64*4882a593Smuzhiyun *
65*4882a593Smuzhiyun * Searchs for a sap in the sap list of the LLC's station upon the sap ID.
66*4882a593Smuzhiyun * If the sap is found it will be refcounted and the user will have to do
67*4882a593Smuzhiyun * a llc_sap_put after use.
68*4882a593Smuzhiyun * Returns the sap or %NULL if not found.
69*4882a593Smuzhiyun */
llc_sap_find(unsigned char sap_value)70*4882a593Smuzhiyun struct llc_sap *llc_sap_find(unsigned char sap_value)
71*4882a593Smuzhiyun {
72*4882a593Smuzhiyun struct llc_sap *sap;
73*4882a593Smuzhiyun
74*4882a593Smuzhiyun rcu_read_lock_bh();
75*4882a593Smuzhiyun sap = __llc_sap_find(sap_value);
76*4882a593Smuzhiyun if (!sap || !llc_sap_hold_safe(sap))
77*4882a593Smuzhiyun sap = NULL;
78*4882a593Smuzhiyun rcu_read_unlock_bh();
79*4882a593Smuzhiyun return sap;
80*4882a593Smuzhiyun }
81*4882a593Smuzhiyun
82*4882a593Smuzhiyun /**
83*4882a593Smuzhiyun * llc_sap_open - open interface to the upper layers.
84*4882a593Smuzhiyun * @lsap: SAP number.
85*4882a593Smuzhiyun * @func: rcv func for datalink protos
86*4882a593Smuzhiyun *
87*4882a593Smuzhiyun * Interface function to upper layer. Each one who wants to get a SAP
88*4882a593Smuzhiyun * (for example NetBEUI) should call this function. Returns the opened
89*4882a593Smuzhiyun * SAP for success, NULL for failure.
90*4882a593Smuzhiyun */
llc_sap_open(unsigned char lsap,int (* func)(struct sk_buff * skb,struct net_device * dev,struct packet_type * pt,struct net_device * orig_dev))91*4882a593Smuzhiyun struct llc_sap *llc_sap_open(unsigned char lsap,
92*4882a593Smuzhiyun int (*func)(struct sk_buff *skb,
93*4882a593Smuzhiyun struct net_device *dev,
94*4882a593Smuzhiyun struct packet_type *pt,
95*4882a593Smuzhiyun struct net_device *orig_dev))
96*4882a593Smuzhiyun {
97*4882a593Smuzhiyun struct llc_sap *sap = NULL;
98*4882a593Smuzhiyun
99*4882a593Smuzhiyun spin_lock_bh(&llc_sap_list_lock);
100*4882a593Smuzhiyun if (__llc_sap_find(lsap)) /* SAP already exists */
101*4882a593Smuzhiyun goto out;
102*4882a593Smuzhiyun sap = llc_sap_alloc();
103*4882a593Smuzhiyun if (!sap)
104*4882a593Smuzhiyun goto out;
105*4882a593Smuzhiyun sap->laddr.lsap = lsap;
106*4882a593Smuzhiyun sap->rcv_func = func;
107*4882a593Smuzhiyun list_add_tail_rcu(&sap->node, &llc_sap_list);
108*4882a593Smuzhiyun out:
109*4882a593Smuzhiyun spin_unlock_bh(&llc_sap_list_lock);
110*4882a593Smuzhiyun return sap;
111*4882a593Smuzhiyun }
112*4882a593Smuzhiyun
113*4882a593Smuzhiyun /**
114*4882a593Smuzhiyun * llc_sap_close - close interface for upper layers.
115*4882a593Smuzhiyun * @sap: SAP to be closed.
116*4882a593Smuzhiyun *
117*4882a593Smuzhiyun * Close interface function to upper layer. Each one who wants to
118*4882a593Smuzhiyun * close an open SAP (for example NetBEUI) should call this function.
119*4882a593Smuzhiyun * Removes this sap from the list of saps in the station and then
120*4882a593Smuzhiyun * frees the memory for this sap.
121*4882a593Smuzhiyun */
llc_sap_close(struct llc_sap * sap)122*4882a593Smuzhiyun void llc_sap_close(struct llc_sap *sap)
123*4882a593Smuzhiyun {
124*4882a593Smuzhiyun WARN_ON(sap->sk_count);
125*4882a593Smuzhiyun
126*4882a593Smuzhiyun spin_lock_bh(&llc_sap_list_lock);
127*4882a593Smuzhiyun list_del_rcu(&sap->node);
128*4882a593Smuzhiyun spin_unlock_bh(&llc_sap_list_lock);
129*4882a593Smuzhiyun
130*4882a593Smuzhiyun kfree_rcu(sap, rcu);
131*4882a593Smuzhiyun }
132*4882a593Smuzhiyun
133*4882a593Smuzhiyun static struct packet_type llc_packet_type __read_mostly = {
134*4882a593Smuzhiyun .type = cpu_to_be16(ETH_P_802_2),
135*4882a593Smuzhiyun .func = llc_rcv,
136*4882a593Smuzhiyun };
137*4882a593Smuzhiyun
138*4882a593Smuzhiyun static struct packet_type llc_tr_packet_type __read_mostly = {
139*4882a593Smuzhiyun .type = cpu_to_be16(ETH_P_TR_802_2),
140*4882a593Smuzhiyun .func = llc_rcv,
141*4882a593Smuzhiyun };
142*4882a593Smuzhiyun
llc_init(void)143*4882a593Smuzhiyun static int __init llc_init(void)
144*4882a593Smuzhiyun {
145*4882a593Smuzhiyun dev_add_pack(&llc_packet_type);
146*4882a593Smuzhiyun dev_add_pack(&llc_tr_packet_type);
147*4882a593Smuzhiyun return 0;
148*4882a593Smuzhiyun }
149*4882a593Smuzhiyun
llc_exit(void)150*4882a593Smuzhiyun static void __exit llc_exit(void)
151*4882a593Smuzhiyun {
152*4882a593Smuzhiyun dev_remove_pack(&llc_packet_type);
153*4882a593Smuzhiyun dev_remove_pack(&llc_tr_packet_type);
154*4882a593Smuzhiyun }
155*4882a593Smuzhiyun
156*4882a593Smuzhiyun module_init(llc_init);
157*4882a593Smuzhiyun module_exit(llc_exit);
158*4882a593Smuzhiyun
159*4882a593Smuzhiyun EXPORT_SYMBOL(llc_sap_list);
160*4882a593Smuzhiyun EXPORT_SYMBOL(llc_sap_find);
161*4882a593Smuzhiyun EXPORT_SYMBOL(llc_sap_open);
162*4882a593Smuzhiyun EXPORT_SYMBOL(llc_sap_close);
163*4882a593Smuzhiyun
164*4882a593Smuzhiyun MODULE_LICENSE("GPL");
165*4882a593Smuzhiyun MODULE_AUTHOR("Procom 1997, Jay Schullist 2001, Arnaldo C. Melo 2001-2003");
166*4882a593Smuzhiyun MODULE_DESCRIPTION("LLC IEEE 802.2 core support");
167