llc_core.c 4.1 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
/*
 * 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>
22
#include <net/net_namespace.h>
L
Linus Torvalds 已提交
23 24 25
#include <net/llc.h>

LIST_HEAD(llc_sap_list);
S
stephen hemminger 已提交
26
static DEFINE_SPINLOCK(llc_sap_list_lock);
L
Linus Torvalds 已提交
27 28 29 30 31 32 33 34

/**
 *	llc_sap_alloc - allocates and initializes sap.
 *
 *	Allocates and initializes sap.
 */
static struct llc_sap *llc_sap_alloc(void)
{
35
	struct llc_sap *sap = kzalloc(sizeof(*sap), GFP_ATOMIC);
36
	int i;
L
Linus Torvalds 已提交
37 38

	if (sap) {
J
Joonwoo Park 已提交
39
		/* sap->laddr.mac - leave as a null, it's filled by bind */
L
Linus Torvalds 已提交
40
		sap->state = LLC_SAP_STATE_ACTIVE;
41
		spin_lock_init(&sap->sk_lock);
42 43
		for (i = 0; i < LLC_SK_LADDR_HASH_ENTRIES; i++)
			INIT_HLIST_NULLS_HEAD(&sap->sk_laddr_hash[i], i);
44
		atomic_set(&sap->refcnt, 1);
L
Linus Torvalds 已提交
45 46 47 48
	}
	return sap;
}

49
static struct llc_sap *__llc_sap_find(unsigned char sap_value)
50
{
51
	struct llc_sap *sap;
52 53 54 55 56 57 58 59 60

	list_for_each_entry(sap, &llc_sap_list, node)
		if (sap->laddr.lsap == sap_value)
			goto out;
	sap = NULL;
out:
	return sap;
}

L
Linus Torvalds 已提交
61 62 63 64 65
/**
 *	llc_sap_find - searchs a SAP in station
 *	@sap_value: sap to be found
 *
 *	Searchs for a sap in the sap list of the LLC's station upon the sap ID.
66 67
 *	If the sap is found it will be refcounted and the user will have to do
 *	a llc_sap_put after use.
L
Linus Torvalds 已提交
68 69 70 71
 *	Returns the sap or %NULL if not found.
 */
struct llc_sap *llc_sap_find(unsigned char sap_value)
{
72
	struct llc_sap *sap;
L
Linus Torvalds 已提交
73

74
	rcu_read_lock_bh();
75 76 77
	sap = __llc_sap_find(sap_value);
	if (sap)
		llc_sap_hold(sap);
78
	rcu_read_unlock_bh();
L
Linus Torvalds 已提交
79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
	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,
D
David S. Miller 已提交
94 95
					 struct packet_type *pt,
					 struct net_device *orig_dev))
L
Linus Torvalds 已提交
96
{
97
	struct llc_sap *sap = NULL;
L
Linus Torvalds 已提交
98

99
	spin_lock_bh(&llc_sap_list_lock);
100
	if (__llc_sap_find(lsap)) /* SAP already exists */
L
Linus Torvalds 已提交
101 102 103 104 105 106
		goto out;
	sap = llc_sap_alloc();
	if (!sap)
		goto out;
	sap->laddr.lsap = lsap;
	sap->rcv_func	= func;
107
	list_add_tail_rcu(&sap->node, &llc_sap_list);
L
Linus Torvalds 已提交
108
out:
109
	spin_unlock_bh(&llc_sap_list_lock);
L
Linus Torvalds 已提交
110 111 112 113 114 115 116 117 118 119 120 121 122 123
	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)
{
124
	WARN_ON(sap->sk_count);
125 126 127 128 129 130 131

	spin_lock_bh(&llc_sap_list_lock);
	list_del_rcu(&sap->node);
	spin_unlock_bh(&llc_sap_list_lock);

	synchronize_rcu();

L
Linus Torvalds 已提交
132 133 134
	kfree(sap);
}

135
static struct packet_type llc_packet_type __read_mostly = {
136
	.type = cpu_to_be16(ETH_P_802_2),
L
Linus Torvalds 已提交
137 138 139
	.func = llc_rcv,
};

140
static struct packet_type llc_tr_packet_type __read_mostly = {
141
	.type = cpu_to_be16(ETH_P_TR_802_2),
L
Linus Torvalds 已提交
142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
	.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");