1
2
3
4
5
6
7
8
9
10
11
12
13
14
15#include <linux/module.h>
16#include <linux/interrupt.h>
17#include <linux/if_ether.h>
18#include <linux/netdevice.h>
19#include <linux/slab.h>
20#include <linux/string.h>
21#include <linux/init.h>
22#include <net/net_namespace.h>
23#include <net/llc.h>
24
25LIST_HEAD(llc_sap_list);
26static DEFINE_SPINLOCK(llc_sap_list_lock);
27
28
29
30
31
32
33static struct llc_sap *llc_sap_alloc(void)
34{
35 struct llc_sap *sap = kzalloc(sizeof(*sap), GFP_ATOMIC);
36 int i;
37
38 if (sap) {
39
40 sap->state = LLC_SAP_STATE_ACTIVE;
41 spin_lock_init(&sap->sk_lock);
42 for (i = 0; i < LLC_SK_LADDR_HASH_ENTRIES; i++)
43 INIT_HLIST_NULLS_HEAD(&sap->sk_laddr_hash[i], i);
44 refcount_set(&sap->refcnt, 1);
45 }
46 return sap;
47}
48
49static struct llc_sap *__llc_sap_find(unsigned char sap_value)
50{
51 struct llc_sap *sap;
52
53 list_for_each_entry(sap, &llc_sap_list, node)
54 if (sap->laddr.lsap == sap_value)
55 goto out;
56 sap = NULL;
57out:
58 return sap;
59}
60
61
62
63
64
65
66
67
68
69
70struct llc_sap *llc_sap_find(unsigned char sap_value)
71{
72 struct llc_sap *sap;
73
74 rcu_read_lock_bh();
75 sap = __llc_sap_find(sap_value);
76 if (!sap || !llc_sap_hold_safe(sap))
77 sap = NULL;
78 rcu_read_unlock_bh();
79 return sap;
80}
81
82
83
84
85
86
87
88
89
90
91struct llc_sap *llc_sap_open(unsigned char lsap,
92 int (*func)(struct sk_buff *skb,
93 struct net_device *dev,
94 struct packet_type *pt,
95 struct net_device *orig_dev))
96{
97 struct llc_sap *sap = NULL;
98
99 spin_lock_bh(&llc_sap_list_lock);
100 if (__llc_sap_find(lsap))
101 goto out;
102 sap = llc_sap_alloc();
103 if (!sap)
104 goto out;
105 sap->laddr.lsap = lsap;
106 sap->rcv_func = func;
107 list_add_tail_rcu(&sap->node, &llc_sap_list);
108out:
109 spin_unlock_bh(&llc_sap_list_lock);
110 return sap;
111}
112
113
114
115
116
117
118
119
120
121
122void llc_sap_close(struct llc_sap *sap)
123{
124 WARN_ON(sap->sk_count);
125
126 spin_lock_bh(&llc_sap_list_lock);
127 list_del_rcu(&sap->node);
128 spin_unlock_bh(&llc_sap_list_lock);
129
130 synchronize_rcu();
131
132 kfree(sap);
133}
134
135static struct packet_type llc_packet_type __read_mostly = {
136 .type = cpu_to_be16(ETH_P_802_2),
137 .func = llc_rcv,
138};
139
140static struct packet_type llc_tr_packet_type __read_mostly = {
141 .type = cpu_to_be16(ETH_P_TR_802_2),
142 .func = llc_rcv,
143};
144
145static int __init llc_init(void)
146{
147 dev_add_pack(&llc_packet_type);
148 dev_add_pack(&llc_tr_packet_type);
149 return 0;
150}
151
152static void __exit llc_exit(void)
153{
154 dev_remove_pack(&llc_packet_type);
155 dev_remove_pack(&llc_tr_packet_type);
156}
157
158module_init(llc_init);
159module_exit(llc_exit);
160
161EXPORT_SYMBOL(llc_sap_list);
162EXPORT_SYMBOL(llc_sap_find);
163EXPORT_SYMBOL(llc_sap_open);
164EXPORT_SYMBOL(llc_sap_close);
165
166MODULE_LICENSE("GPL");
167MODULE_AUTHOR("Procom 1997, Jay Schullist 2001, Arnaldo C. Melo 2001-2003");
168MODULE_DESCRIPTION("LLC IEEE 802.2 core support");
169