llc_core.c 4.7 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 22 23 24 25 26 27 28 29 30 31 32 33 34 35
/*
 * 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>
#include <net/llc.h>

LIST_HEAD(llc_sap_list);
DEFINE_RWLOCK(llc_sap_list_lock);

unsigned char llc_station_mac_sa[ETH_ALEN];

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

	if (sap) {
		sap->state = LLC_SAP_STATE_ACTIVE;
		memcpy(sap->laddr.mac, llc_station_mac_sa, ETH_ALEN);
		rwlock_init(&sap->sk_list.lock);
42
		atomic_set(&sap->refcnt, 1);
L
Linus Torvalds 已提交
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
	}
	return sap;
}

/**
 *	llc_add_sap - add sap to station list
 *	@sap: Address of the sap
 *
 *	Adds a sap to the LLC's station sap list.
 */
static void llc_add_sap(struct llc_sap *sap)
{
	list_add_tail(&sap->node, &llc_sap_list);
}

/**
 *	llc_del_sap - del sap from station list
 *	@sap: Address of the sap
 *
 *	Removes a sap to the LLC's station sap list.
 */
static void llc_del_sap(struct llc_sap *sap)
{
	write_lock_bh(&llc_sap_list_lock);
	list_del(&sap->node);
	write_unlock_bh(&llc_sap_list_lock);
}

71
static struct llc_sap *__llc_sap_find(unsigned char sap_value)
72 73 74 75 76 77 78 79 80 81 82
{
	struct llc_sap* sap;

	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 已提交
83 84 85 86 87
/**
 *	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.
88 89
 *	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 已提交
90 91 92 93 94 95 96
 *	Returns the sap or %NULL if not found.
 */
struct llc_sap *llc_sap_find(unsigned char sap_value)
{
	struct llc_sap* sap;

	read_lock_bh(&llc_sap_list_lock);
97 98 99
	sap = __llc_sap_find(sap_value);
	if (sap)
		llc_sap_hold(sap);
L
Linus Torvalds 已提交
100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115
	read_unlock_bh(&llc_sap_list_lock);
	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 已提交
116 117
					 struct packet_type *pt,
					 struct net_device *orig_dev))
L
Linus Torvalds 已提交
118
{
119
	struct llc_sap *sap = NULL;
L
Linus Torvalds 已提交
120

121 122
	write_lock_bh(&llc_sap_list_lock);
	if (__llc_sap_find(lsap)) /* SAP already exists */
L
Linus Torvalds 已提交
123 124 125 126 127 128 129 130
		goto out;
	sap = llc_sap_alloc();
	if (!sap)
		goto out;
	sap->laddr.lsap = lsap;
	sap->rcv_func	= func;
	llc_add_sap(sap);
out:
131
	write_unlock_bh(&llc_sap_list_lock);
L
Linus Torvalds 已提交
132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162
	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)
{
	WARN_ON(!hlist_empty(&sap->sk_list.list));
	llc_del_sap(sap);
	kfree(sap);
}

static struct packet_type llc_packet_type = {
	.type = __constant_htons(ETH_P_802_2),
	.func = llc_rcv,
};

static struct packet_type llc_tr_packet_type = {
	.type = __constant_htons(ETH_P_TR_802_2),
	.func = llc_rcv,
};

static int __init llc_init(void)
{
163 164 165 166 167 168 169 170
	struct net_device *dev;

	dev = first_net_device();
	if (dev != NULL)
		dev = next_net_device(dev);

	if (dev != NULL)
		memcpy(llc_station_mac_sa, dev->dev_addr, ETH_ALEN);
L
Linus Torvalds 已提交
171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196
	else
		memset(llc_station_mac_sa, 0, ETH_ALEN);
	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_station_mac_sa);
EXPORT_SYMBOL(llc_sap_list);
EXPORT_SYMBOL(llc_sap_list_lock);
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");