/* Copyright (C) 2000-2002 Joakim Axelsson * Patrick Schaaf * Martin Josefsson * Copyright (C) 2003-2008 Jozsef Kadlecsik * * 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 #include #include #include #include #include #include #include #include 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 "); MODULE_DESCRIPTION("macipmap type of IP sets"); REGISTER_MODULE(macipmap)