Path: blob/master/net/netlabel/netlabel_addrlist.c
15109 views
/*1* NetLabel Network Address Lists2*3* This file contains network address list functions used to manage ordered4* lists of network addresses for use by the NetLabel subsystem. The NetLabel5* system manages static and dynamic label mappings for network protocols such6* as CIPSO and RIPSO.7*8* Author: Paul Moore <[email protected]>9*10*/1112/*13* (c) Copyright Hewlett-Packard Development Company, L.P., 200814*15* This program is free software; you can redistribute it and/or modify16* it under the terms of the GNU General Public License as published by17* the Free Software Foundation; either version 2 of the License, or18* (at your option) any later version.19*20* This program is distributed in the hope that it will be useful,21* but WITHOUT ANY WARRANTY; without even the implied warranty of22* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See23* the GNU General Public License for more details.24*25* You should have received a copy of the GNU General Public License26* along with this program; if not, write to the Free Software27* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA28*29*/3031#include <linux/types.h>32#include <linux/rcupdate.h>33#include <linux/list.h>34#include <linux/spinlock.h>35#include <linux/in.h>36#include <linux/in6.h>37#include <linux/ip.h>38#include <linux/ipv6.h>39#include <net/ip.h>40#include <net/ipv6.h>41#include <linux/audit.h>4243#include "netlabel_addrlist.h"4445/*46* Address List Functions47*/4849/**50* netlbl_af4list_search - Search for a matching IPv4 address entry51* @addr: IPv4 address52* @head: the list head53*54* Description:55* Searches the IPv4 address list given by @head. If a matching address entry56* is found it is returned, otherwise NULL is returned. The caller is57* responsible for calling the rcu_read_[un]lock() functions.58*59*/60struct netlbl_af4list *netlbl_af4list_search(__be32 addr,61struct list_head *head)62{63struct netlbl_af4list *iter;6465list_for_each_entry_rcu(iter, head, list)66if (iter->valid && (addr & iter->mask) == iter->addr)67return iter;6869return NULL;70}7172/**73* netlbl_af4list_search_exact - Search for an exact IPv4 address entry74* @addr: IPv4 address75* @mask: IPv4 address mask76* @head: the list head77*78* Description:79* Searches the IPv4 address list given by @head. If an exact match if found80* it is returned, otherwise NULL is returned. The caller is responsible for81* calling the rcu_read_[un]lock() functions.82*83*/84struct netlbl_af4list *netlbl_af4list_search_exact(__be32 addr,85__be32 mask,86struct list_head *head)87{88struct netlbl_af4list *iter;8990list_for_each_entry_rcu(iter, head, list)91if (iter->valid && iter->addr == addr && iter->mask == mask)92return iter;9394return NULL;95}969798#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)99/**100* netlbl_af6list_search - Search for a matching IPv6 address entry101* @addr: IPv6 address102* @head: the list head103*104* Description:105* Searches the IPv6 address list given by @head. If a matching address entry106* is found it is returned, otherwise NULL is returned. The caller is107* responsible for calling the rcu_read_[un]lock() functions.108*109*/110struct netlbl_af6list *netlbl_af6list_search(const struct in6_addr *addr,111struct list_head *head)112{113struct netlbl_af6list *iter;114115list_for_each_entry_rcu(iter, head, list)116if (iter->valid &&117ipv6_masked_addr_cmp(&iter->addr, &iter->mask, addr) == 0)118return iter;119120return NULL;121}122123/**124* netlbl_af6list_search_exact - Search for an exact IPv6 address entry125* @addr: IPv6 address126* @mask: IPv6 address mask127* @head: the list head128*129* Description:130* Searches the IPv6 address list given by @head. If an exact match if found131* it is returned, otherwise NULL is returned. The caller is responsible for132* calling the rcu_read_[un]lock() functions.133*134*/135struct netlbl_af6list *netlbl_af6list_search_exact(const struct in6_addr *addr,136const struct in6_addr *mask,137struct list_head *head)138{139struct netlbl_af6list *iter;140141list_for_each_entry_rcu(iter, head, list)142if (iter->valid &&143ipv6_addr_equal(&iter->addr, addr) &&144ipv6_addr_equal(&iter->mask, mask))145return iter;146147return NULL;148}149#endif /* IPv6 */150151/**152* netlbl_af4list_add - Add a new IPv4 address entry to a list153* @entry: address entry154* @head: the list head155*156* Description:157* Add a new address entry to the list pointed to by @head. On success zero is158* returned, otherwise a negative value is returned. The caller is responsible159* for calling the necessary locking functions.160*161*/162int netlbl_af4list_add(struct netlbl_af4list *entry, struct list_head *head)163{164struct netlbl_af4list *iter;165166iter = netlbl_af4list_search(entry->addr, head);167if (iter != NULL &&168iter->addr == entry->addr && iter->mask == entry->mask)169return -EEXIST;170171/* in order to speed up address searches through the list (the common172* case) we need to keep the list in order based on the size of the173* address mask such that the entry with the widest mask (smallest174* numerical value) appears first in the list */175list_for_each_entry_rcu(iter, head, list)176if (iter->valid &&177ntohl(entry->mask) > ntohl(iter->mask)) {178__list_add_rcu(&entry->list,179iter->list.prev,180&iter->list);181return 0;182}183list_add_tail_rcu(&entry->list, head);184return 0;185}186187#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)188/**189* netlbl_af6list_add - Add a new IPv6 address entry to a list190* @entry: address entry191* @head: the list head192*193* Description:194* Add a new address entry to the list pointed to by @head. On success zero is195* returned, otherwise a negative value is returned. The caller is responsible196* for calling the necessary locking functions.197*198*/199int netlbl_af6list_add(struct netlbl_af6list *entry, struct list_head *head)200{201struct netlbl_af6list *iter;202203iter = netlbl_af6list_search(&entry->addr, head);204if (iter != NULL &&205ipv6_addr_equal(&iter->addr, &entry->addr) &&206ipv6_addr_equal(&iter->mask, &entry->mask))207return -EEXIST;208209/* in order to speed up address searches through the list (the common210* case) we need to keep the list in order based on the size of the211* address mask such that the entry with the widest mask (smallest212* numerical value) appears first in the list */213list_for_each_entry_rcu(iter, head, list)214if (iter->valid &&215ipv6_addr_cmp(&entry->mask, &iter->mask) > 0) {216__list_add_rcu(&entry->list,217iter->list.prev,218&iter->list);219return 0;220}221list_add_tail_rcu(&entry->list, head);222return 0;223}224#endif /* IPv6 */225226/**227* netlbl_af4list_remove_entry - Remove an IPv4 address entry228* @entry: address entry229*230* Description:231* Remove the specified IP address entry. The caller is responsible for232* calling the necessary locking functions.233*234*/235void netlbl_af4list_remove_entry(struct netlbl_af4list *entry)236{237entry->valid = 0;238list_del_rcu(&entry->list);239}240241/**242* netlbl_af4list_remove - Remove an IPv4 address entry243* @addr: IP address244* @mask: IP address mask245* @head: the list head246*247* Description:248* Remove an IP address entry from the list pointed to by @head. Returns the249* entry on success, NULL on failure. The caller is responsible for calling250* the necessary locking functions.251*252*/253struct netlbl_af4list *netlbl_af4list_remove(__be32 addr, __be32 mask,254struct list_head *head)255{256struct netlbl_af4list *entry;257258entry = netlbl_af4list_search_exact(addr, mask, head);259if (entry == NULL)260return NULL;261netlbl_af4list_remove_entry(entry);262return entry;263}264265#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)266/**267* netlbl_af6list_remove_entry - Remove an IPv6 address entry268* @entry: address entry269*270* Description:271* Remove the specified IP address entry. The caller is responsible for272* calling the necessary locking functions.273*274*/275void netlbl_af6list_remove_entry(struct netlbl_af6list *entry)276{277entry->valid = 0;278list_del_rcu(&entry->list);279}280281/**282* netlbl_af6list_remove - Remove an IPv6 address entry283* @addr: IP address284* @mask: IP address mask285* @head: the list head286*287* Description:288* Remove an IP address entry from the list pointed to by @head. Returns the289* entry on success, NULL on failure. The caller is responsible for calling290* the necessary locking functions.291*292*/293struct netlbl_af6list *netlbl_af6list_remove(const struct in6_addr *addr,294const struct in6_addr *mask,295struct list_head *head)296{297struct netlbl_af6list *entry;298299entry = netlbl_af6list_search_exact(addr, mask, head);300if (entry == NULL)301return NULL;302netlbl_af6list_remove_entry(entry);303return entry;304}305#endif /* IPv6 */306307/*308* Audit Helper Functions309*/310311#ifdef CONFIG_AUDIT312/**313* netlbl_af4list_audit_addr - Audit an IPv4 address314* @audit_buf: audit buffer315* @src: true if source address, false if destination316* @dev: network interface317* @addr: IP address318* @mask: IP address mask319*320* Description:321* Write the IPv4 address and address mask, if necessary, to @audit_buf.322*323*/324void netlbl_af4list_audit_addr(struct audit_buffer *audit_buf,325int src, const char *dev,326__be32 addr, __be32 mask)327{328u32 mask_val = ntohl(mask);329char *dir = (src ? "src" : "dst");330331if (dev != NULL)332audit_log_format(audit_buf, " netif=%s", dev);333audit_log_format(audit_buf, " %s=%pI4", dir, &addr);334if (mask_val != 0xffffffff) {335u32 mask_len = 0;336while (mask_val > 0) {337mask_val <<= 1;338mask_len++;339}340audit_log_format(audit_buf, " %s_prefixlen=%d", dir, mask_len);341}342}343344#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)345/**346* netlbl_af6list_audit_addr - Audit an IPv6 address347* @audit_buf: audit buffer348* @src: true if source address, false if destination349* @dev: network interface350* @addr: IP address351* @mask: IP address mask352*353* Description:354* Write the IPv6 address and address mask, if necessary, to @audit_buf.355*356*/357void netlbl_af6list_audit_addr(struct audit_buffer *audit_buf,358int src,359const char *dev,360const struct in6_addr *addr,361const struct in6_addr *mask)362{363char *dir = (src ? "src" : "dst");364365if (dev != NULL)366audit_log_format(audit_buf, " netif=%s", dev);367audit_log_format(audit_buf, " %s=%pI6", dir, addr);368if (ntohl(mask->s6_addr32[3]) != 0xffffffff) {369u32 mask_len = 0;370u32 mask_val;371int iter = -1;372while (ntohl(mask->s6_addr32[++iter]) == 0xffffffff)373mask_len += 32;374mask_val = ntohl(mask->s6_addr32[iter]);375while (mask_val > 0) {376mask_val <<= 1;377mask_len++;378}379audit_log_format(audit_buf, " %s_prefixlen=%d", dir, mask_len);380}381}382#endif /* IPv6 */383#endif /* CONFIG_AUDIT */384385386