0001
0002
0003
0004
0005
0006
0007 #include <linux/mutex.h>
0008 #include <linux/skbuff.h>
0009 #include <linux/etherdevice.h>
0010 #include <linux/llc.h>
0011 #include <linux/slab.h>
0012 #include <linux/module.h>
0013 #include <net/llc.h>
0014 #include <net/llc_pdu.h>
0015 #include <net/stp.h>
0016
0017
0018 #define GARP_ADDR_MIN 0x20
0019 #define GARP_ADDR_MAX 0x2F
0020 #define GARP_ADDR_RANGE (GARP_ADDR_MAX - GARP_ADDR_MIN)
0021
0022 static const struct stp_proto __rcu *garp_protos[GARP_ADDR_RANGE + 1] __read_mostly;
0023 static const struct stp_proto __rcu *stp_proto __read_mostly;
0024
0025 static struct llc_sap *sap __read_mostly;
0026 static unsigned int sap_registered;
0027 static DEFINE_MUTEX(stp_proto_mutex);
0028
0029
0030 static int stp_pdu_rcv(struct sk_buff *skb, struct net_device *dev,
0031 struct packet_type *pt, struct net_device *orig_dev)
0032 {
0033 const struct ethhdr *eh = eth_hdr(skb);
0034 const struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb);
0035 const struct stp_proto *proto;
0036
0037 if (pdu->ssap != LLC_SAP_BSPAN ||
0038 pdu->dsap != LLC_SAP_BSPAN ||
0039 pdu->ctrl_1 != LLC_PDU_TYPE_U)
0040 goto err;
0041
0042 if (eh->h_dest[5] >= GARP_ADDR_MIN && eh->h_dest[5] <= GARP_ADDR_MAX) {
0043 proto = rcu_dereference(garp_protos[eh->h_dest[5] -
0044 GARP_ADDR_MIN]);
0045 if (proto &&
0046 !ether_addr_equal(eh->h_dest, proto->group_address))
0047 goto err;
0048 } else
0049 proto = rcu_dereference(stp_proto);
0050
0051 if (!proto)
0052 goto err;
0053
0054 proto->rcv(proto, skb, dev);
0055 return 0;
0056
0057 err:
0058 kfree_skb(skb);
0059 return 0;
0060 }
0061
0062 int stp_proto_register(const struct stp_proto *proto)
0063 {
0064 int err = 0;
0065
0066 mutex_lock(&stp_proto_mutex);
0067 if (sap_registered++ == 0) {
0068 sap = llc_sap_open(LLC_SAP_BSPAN, stp_pdu_rcv);
0069 if (!sap) {
0070 err = -ENOMEM;
0071 goto out;
0072 }
0073 }
0074 if (is_zero_ether_addr(proto->group_address))
0075 rcu_assign_pointer(stp_proto, proto);
0076 else
0077 rcu_assign_pointer(garp_protos[proto->group_address[5] -
0078 GARP_ADDR_MIN], proto);
0079 out:
0080 mutex_unlock(&stp_proto_mutex);
0081 return err;
0082 }
0083 EXPORT_SYMBOL_GPL(stp_proto_register);
0084
0085 void stp_proto_unregister(const struct stp_proto *proto)
0086 {
0087 mutex_lock(&stp_proto_mutex);
0088 if (is_zero_ether_addr(proto->group_address))
0089 RCU_INIT_POINTER(stp_proto, NULL);
0090 else
0091 RCU_INIT_POINTER(garp_protos[proto->group_address[5] -
0092 GARP_ADDR_MIN], NULL);
0093 synchronize_rcu();
0094
0095 if (--sap_registered == 0)
0096 llc_sap_put(sap);
0097 mutex_unlock(&stp_proto_mutex);
0098 }
0099 EXPORT_SYMBOL_GPL(stp_proto_unregister);
0100
0101 MODULE_LICENSE("GPL");