aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPatrick McHardy <kaber@trash.net>2008-07-06 00:25:39 -0400
committerDavid S. Miller <davem@davemloft.net>2008-07-06 00:25:39 -0400
commita19800d704177caaa5874baf5819307c5b7d5e4f (patch)
treeebe3397dc06ff3544a09f078f512cadb996daaf9
parentef28d1a20f9f18ebf1be15ef6f097a76f9a63499 (diff)
net: Add STP demux layer
Add small STP demux layer for demuxing STP PDUs based on MAC address. This is needed to run both GARP and STP in parallel (or even load the modules) since both use LLC_SAP_BSPAN. Signed-off-by: Patrick McHardy <kaber@trash.net> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/net/stp.h14
-rw-r--r--net/802/Kconfig3
-rw-r--r--net/802/Makefile1
-rw-r--r--net/802/stp.c102
-rw-r--r--net/Kconfig1
5 files changed, 121 insertions, 0 deletions
diff --git a/include/net/stp.h b/include/net/stp.h
new file mode 100644
index 000000000000..ad447f105417
--- /dev/null
+++ b/include/net/stp.h
@@ -0,0 +1,14 @@
1#ifndef _NET_STP_H
2#define _NET_STP_H
3
4struct stp_proto {
5 unsigned char group_address[ETH_ALEN];
6 void (*rcv)(const struct stp_proto *, struct sk_buff *,
7 struct net_device *);
8 void *data;
9};
10
11extern int stp_proto_register(const struct stp_proto *proto);
12extern void stp_proto_unregister(const struct stp_proto *proto);
13
14#endif /* _NET_STP_H */
diff --git a/net/802/Kconfig b/net/802/Kconfig
new file mode 100644
index 000000000000..01cb0943626b
--- /dev/null
+++ b/net/802/Kconfig
@@ -0,0 +1,3 @@
1config STP
2 tristate
3 select LLC
diff --git a/net/802/Makefile b/net/802/Makefile
index 68569ffddea1..c441d895ac25 100644
--- a/net/802/Makefile
+++ b/net/802/Makefile
@@ -10,3 +10,4 @@ obj-$(CONFIG_FDDI) += fddi.o
10obj-$(CONFIG_HIPPI) += hippi.o 10obj-$(CONFIG_HIPPI) += hippi.o
11obj-$(CONFIG_IPX) += p8022.o psnap.o p8023.o 11obj-$(CONFIG_IPX) += p8022.o psnap.o p8023.o
12obj-$(CONFIG_ATALK) += p8022.o psnap.o 12obj-$(CONFIG_ATALK) += p8022.o psnap.o
13obj-$(CONFIG_STP) += stp.o
diff --git a/net/802/stp.c b/net/802/stp.c
new file mode 100644
index 000000000000..0b7a24452d11
--- /dev/null
+++ b/net/802/stp.c
@@ -0,0 +1,102 @@
1/*
2 * STP SAP demux
3 *
4 * Copyright (c) 2008 Patrick McHardy <kaber@trash.net>
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * version 2 as published by the Free Software Foundation.
9 */
10#include <linux/mutex.h>
11#include <linux/skbuff.h>
12#include <linux/etherdevice.h>
13#include <linux/llc.h>
14#include <net/llc.h>
15#include <net/llc_pdu.h>
16#include <net/stp.h>
17
18/* 01:80:c2:00:00:20 - 01:80:c2:00:00:2F */
19#define GARP_ADDR_MIN 0x20
20#define GARP_ADDR_MAX 0x2F
21#define GARP_ADDR_RANGE (GARP_ADDR_MAX - GARP_ADDR_MIN)
22
23static const struct stp_proto *garp_protos[GARP_ADDR_RANGE + 1] __read_mostly;
24static const struct stp_proto *stp_proto __read_mostly;
25
26static struct llc_sap *sap __read_mostly;
27static unsigned int sap_registered;
28static DEFINE_MUTEX(stp_proto_mutex);
29
30/* Called under rcu_read_lock from LLC */
31static int stp_pdu_rcv(struct sk_buff *skb, struct net_device *dev,
32 struct packet_type *pt, struct net_device *orig_dev)
33{
34 const struct ethhdr *eh = eth_hdr(skb);
35 const struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb);
36 const struct stp_proto *proto;
37
38 if (pdu->ssap != LLC_SAP_BSPAN ||
39 pdu->dsap != LLC_SAP_BSPAN ||
40 pdu->ctrl_1 != LLC_PDU_TYPE_U)
41 goto err;
42
43 if (eh->h_dest[5] >= GARP_ADDR_MIN && eh->h_dest[5] <= GARP_ADDR_MAX) {
44 proto = rcu_dereference(garp_protos[eh->h_dest[5] -
45 GARP_ADDR_MIN]);
46 if (proto &&
47 compare_ether_addr(eh->h_dest, proto->group_address))
48 goto err;
49 } else
50 proto = rcu_dereference(stp_proto);
51
52 if (!proto)
53 goto err;
54
55 proto->rcv(proto, skb, dev);
56 return 0;
57
58err:
59 kfree_skb(skb);
60 return 0;
61}
62
63int stp_proto_register(const struct stp_proto *proto)
64{
65 int err = 0;
66
67 mutex_lock(&stp_proto_mutex);
68 if (sap_registered++ == 0) {
69 sap = llc_sap_open(LLC_SAP_BSPAN, stp_pdu_rcv);
70 if (!sap) {
71 err = -ENOMEM;
72 goto out;
73 }
74 }
75 if (is_zero_ether_addr(proto->group_address))
76 rcu_assign_pointer(stp_proto, proto);
77 else
78 rcu_assign_pointer(garp_protos[proto->group_address[5] -
79 GARP_ADDR_MIN], proto);
80out:
81 mutex_unlock(&stp_proto_mutex);
82 return err;
83}
84EXPORT_SYMBOL_GPL(stp_proto_register);
85
86void stp_proto_unregister(const struct stp_proto *proto)
87{
88 mutex_lock(&stp_proto_mutex);
89 if (is_zero_ether_addr(proto->group_address))
90 rcu_assign_pointer(stp_proto, NULL);
91 else
92 rcu_assign_pointer(garp_protos[proto->group_address[5] -
93 GARP_ADDR_MIN], NULL);
94 synchronize_rcu();
95
96 if (--sap_registered == 0)
97 llc_sap_put(sap);
98 mutex_unlock(&stp_proto_mutex);
99}
100EXPORT_SYMBOL_GPL(stp_proto_unregister);
101
102MODULE_LICENSE("GPL");
diff --git a/net/Kconfig b/net/Kconfig
index acbf7c60e89b..b98668751749 100644
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -181,6 +181,7 @@ source "net/dccp/Kconfig"
181source "net/sctp/Kconfig" 181source "net/sctp/Kconfig"
182source "net/tipc/Kconfig" 182source "net/tipc/Kconfig"
183source "net/atm/Kconfig" 183source "net/atm/Kconfig"
184source "net/802/Kconfig"
184source "net/bridge/Kconfig" 185source "net/bridge/Kconfig"
185source "net/8021q/Kconfig" 186source "net/8021q/Kconfig"
186source "net/decnet/Kconfig" 187source "net/decnet/Kconfig"