summaryrefslogtreecommitdiffstats
path: root/kernel/ip_set_bitmap_ipmac.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/ip_set_bitmap_ipmac.c')
-rw-r--r--kernel/ip_set_bitmap_ipmac.c179
1 files changed, 179 insertions, 0 deletions
diff --git a/kernel/ip_set_bitmap_ipmac.c b/kernel/ip_set_bitmap_ipmac.c
new file mode 100644
index 0000000..89e907b
--- /dev/null
+++ b/kernel/ip_set_bitmap_ipmac.c
@@ -0,0 +1,179 @@
+/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
+ * Patrick Schaaf <bof@bof.de>
+ * Martin Josefsson <gandalf@wlug.westbo.se>
+ * Copyright (C) 2003-2008 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+/* Kernel module implementing an IP set type: the macipmap type */
+
+#include <linux/module.h>
+#include <linux/ip.h>
+#include <linux/skbuff.h>
+#include <linux/errno.h>
+#include <asm/uaccess.h>
+#include <asm/bitops.h>
+#include <linux/spinlock.h>
+#include <linux/if_ether.h>
+
+#include <linux/netfilter_ipv4/ip_set_macipmap.h>
+
+static int
+macipmap_utest(struct ip_set *set, const void *data, u_int32_t size)
+{
+ const struct ip_set_macipmap *map = set->data;
+ const struct ip_set_macip *table = map->members;
+ const struct ip_set_req_macipmap *req = data;
+
+ if (req->ip < map->first_ip || req->ip > map->last_ip)
+ return -ERANGE;
+
+ DP("set: %s, ip:%u.%u.%u.%u", set->name, HIPQUAD(req->ip));
+ if (table[req->ip - map->first_ip].match) {
+ return (memcmp(req->ethernet,
+ &table[req->ip - map->first_ip].ethernet,
+ ETH_ALEN) == 0);
+ } else {
+ return (map->flags & IPSET_MACIP_MATCHUNSET ? 1 : 0);
+ }
+}
+
+static int
+macipmap_ktest(struct ip_set *set,
+ const struct sk_buff *skb,
+ const u_int32_t *flags)
+{
+ const struct ip_set_macipmap *map = set->data;
+ const struct ip_set_macip *table = map->members;
+ ip_set_ip_t ip;
+
+ ip = ipaddr(skb, flags);
+
+ if (ip < map->first_ip || ip > map->last_ip)
+ return 0;
+
+ DP("set: %s, ip:%u.%u.%u.%u", set->name, HIPQUAD(ip));
+ if (table[ip - map->first_ip].match) {
+ /* Is mac pointer valid?
+ * If so, compare... */
+ return (skb_mac_header(skb) >= skb->head
+ && (skb_mac_header(skb) + ETH_HLEN) <= skb->data
+ && (memcmp(eth_hdr(skb)->h_source,
+ &table[ip - map->first_ip].ethernet,
+ ETH_ALEN) == 0));
+ } else {
+ return (map->flags & IPSET_MACIP_MATCHUNSET ? 1 : 0);
+ }
+}
+
+/* returns 0 on success */
+static inline int
+macipmap_add(struct ip_set *set,
+ ip_set_ip_t ip, const unsigned char *ethernet)
+{
+ struct ip_set_macipmap *map = set->data;
+ struct ip_set_macip *table = map->members;
+
+ if (ip < map->first_ip || ip > map->last_ip)
+ return -ERANGE;
+ if (table[ip - map->first_ip].match)
+ return -EEXIST;
+
+ DP("set: %s, ip: %u.%u.%u.%u", set->name, HIPQUAD(ip));
+ memcpy(&table[ip - map->first_ip].ethernet, ethernet, ETH_ALEN);
+ table[ip - map->first_ip].match = IPSET_MACIP_ISSET;
+ return 0;
+}
+
+#define KADT_CONDITION \
+ if (!(skb_mac_header(skb) >= skb->head \
+ && (skb_mac_header(skb) + ETH_HLEN) <= skb->data))\
+ return -EINVAL;
+
+UADT(macipmap, add, req->ethernet)
+KADT(macipmap, add, ipaddr, eth_hdr(skb)->h_source)
+
+static inline int
+macipmap_del(struct ip_set *set, ip_set_ip_t ip)
+{
+ struct ip_set_macipmap *map = set->data;
+ struct ip_set_macip *table = map->members;
+
+ if (ip < map->first_ip || ip > map->last_ip)
+ return -ERANGE;
+ if (!table[ip - map->first_ip].match)
+ return -EEXIST;
+
+ table[ip - map->first_ip].match = 0;
+ DP("set: %s, ip: %u.%u.%u.%u", set->name, HIPQUAD(ip));
+ return 0;
+}
+
+#undef KADT_CONDITION
+#define KADT_CONDITION
+
+UADT(macipmap, del)
+KADT(macipmap, del, ipaddr)
+
+static inline int
+__macipmap_create(const struct ip_set_req_macipmap_create *req,
+ struct ip_set_macipmap *map)
+{
+ if (req->to - req->from > MAX_RANGE) {
+ ip_set_printk("range too big, %d elements (max %d)",
+ req->to - req->from + 1, MAX_RANGE+1);
+ return -ENOEXEC;
+ }
+ map->flags = req->flags;
+ return (req->to - req->from + 1) * sizeof(struct ip_set_macip);
+}
+
+BITMAP_CREATE(macipmap)
+BITMAP_DESTROY(macipmap)
+BITMAP_FLUSH(macipmap)
+
+static inline void
+__macipmap_list_header(const struct ip_set_macipmap *map,
+ struct ip_set_req_macipmap_create *header)
+{
+ header->flags = map->flags;
+}
+
+BITMAP_LIST_HEADER(macipmap)
+BITMAP_LIST_MEMBERS_SIZE(macipmap, struct ip_set_req_macipmap,
+ (map->last_ip - map->first_ip + 1),
+ ((const struct ip_set_macip *)map->members)[i].match)
+
+
+static void
+macipmap_list_members(const struct ip_set *set, void *data, char dont_align)
+{
+ const struct ip_set_macipmap *map = set->data;
+ const struct ip_set_macip *table = map->members;
+ uint32_t i, n = 0;
+ struct ip_set_req_macipmap *d;
+
+ if (dont_align) {
+ memcpy(data, map->members, map->size);
+ return;
+ }
+
+ for (i = 0; i < map->last_ip - map->first_ip + 1; i++)
+ if (table[i].match) {
+ d = data + n * IPSET_ALIGN(sizeof(struct ip_set_req_macipmap));
+ d->ip = map->first_ip + i;
+ memcpy(d->ethernet, &table[i].ethernet, ETH_ALEN);
+ n++;
+ }
+}
+
+IP_SET_TYPE(macipmap, IPSET_TYPE_IP | IPSET_DATA_SINGLE)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
+MODULE_DESCRIPTION("macipmap type of IP sets");
+
+REGISTER_MODULE(macipmap)