18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * NetLabel Network Address Lists
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * This file contains network address list functions used to manage ordered
68c2ecf20Sopenharmony_ci * lists of network addresses for use by the NetLabel subsystem.  The NetLabel
78c2ecf20Sopenharmony_ci * system manages static and dynamic label mappings for network protocols such
88c2ecf20Sopenharmony_ci * as CIPSO and RIPSO.
98c2ecf20Sopenharmony_ci *
108c2ecf20Sopenharmony_ci * Author: Paul Moore <paul@paul-moore.com>
118c2ecf20Sopenharmony_ci */
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci/*
148c2ecf20Sopenharmony_ci * (c) Copyright Hewlett-Packard Development Company, L.P., 2008
158c2ecf20Sopenharmony_ci */
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci#include <linux/types.h>
188c2ecf20Sopenharmony_ci#include <linux/rcupdate.h>
198c2ecf20Sopenharmony_ci#include <linux/list.h>
208c2ecf20Sopenharmony_ci#include <linux/spinlock.h>
218c2ecf20Sopenharmony_ci#include <linux/in.h>
228c2ecf20Sopenharmony_ci#include <linux/in6.h>
238c2ecf20Sopenharmony_ci#include <linux/ip.h>
248c2ecf20Sopenharmony_ci#include <linux/ipv6.h>
258c2ecf20Sopenharmony_ci#include <net/ip.h>
268c2ecf20Sopenharmony_ci#include <net/ipv6.h>
278c2ecf20Sopenharmony_ci#include <linux/audit.h>
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci#include "netlabel_addrlist.h"
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci/*
328c2ecf20Sopenharmony_ci * Address List Functions
338c2ecf20Sopenharmony_ci */
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci/**
368c2ecf20Sopenharmony_ci * netlbl_af4list_search - Search for a matching IPv4 address entry
378c2ecf20Sopenharmony_ci * @addr: IPv4 address
388c2ecf20Sopenharmony_ci * @head: the list head
398c2ecf20Sopenharmony_ci *
408c2ecf20Sopenharmony_ci * Description:
418c2ecf20Sopenharmony_ci * Searches the IPv4 address list given by @head.  If a matching address entry
428c2ecf20Sopenharmony_ci * is found it is returned, otherwise NULL is returned.  The caller is
438c2ecf20Sopenharmony_ci * responsible for calling the rcu_read_[un]lock() functions.
448c2ecf20Sopenharmony_ci *
458c2ecf20Sopenharmony_ci */
468c2ecf20Sopenharmony_cistruct netlbl_af4list *netlbl_af4list_search(__be32 addr,
478c2ecf20Sopenharmony_ci					     struct list_head *head)
488c2ecf20Sopenharmony_ci{
498c2ecf20Sopenharmony_ci	struct netlbl_af4list *iter;
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci	list_for_each_entry_rcu(iter, head, list)
528c2ecf20Sopenharmony_ci		if (iter->valid && (addr & iter->mask) == iter->addr)
538c2ecf20Sopenharmony_ci			return iter;
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci	return NULL;
568c2ecf20Sopenharmony_ci}
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci/**
598c2ecf20Sopenharmony_ci * netlbl_af4list_search_exact - Search for an exact IPv4 address entry
608c2ecf20Sopenharmony_ci * @addr: IPv4 address
618c2ecf20Sopenharmony_ci * @mask: IPv4 address mask
628c2ecf20Sopenharmony_ci * @head: the list head
638c2ecf20Sopenharmony_ci *
648c2ecf20Sopenharmony_ci * Description:
658c2ecf20Sopenharmony_ci * Searches the IPv4 address list given by @head.  If an exact match if found
668c2ecf20Sopenharmony_ci * it is returned, otherwise NULL is returned.  The caller is responsible for
678c2ecf20Sopenharmony_ci * calling the rcu_read_[un]lock() functions.
688c2ecf20Sopenharmony_ci *
698c2ecf20Sopenharmony_ci */
708c2ecf20Sopenharmony_cistruct netlbl_af4list *netlbl_af4list_search_exact(__be32 addr,
718c2ecf20Sopenharmony_ci						   __be32 mask,
728c2ecf20Sopenharmony_ci						   struct list_head *head)
738c2ecf20Sopenharmony_ci{
748c2ecf20Sopenharmony_ci	struct netlbl_af4list *iter;
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci	list_for_each_entry_rcu(iter, head, list)
778c2ecf20Sopenharmony_ci		if (iter->valid && iter->addr == addr && iter->mask == mask)
788c2ecf20Sopenharmony_ci			return iter;
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci	return NULL;
818c2ecf20Sopenharmony_ci}
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6)
858c2ecf20Sopenharmony_ci/**
868c2ecf20Sopenharmony_ci * netlbl_af6list_search - Search for a matching IPv6 address entry
878c2ecf20Sopenharmony_ci * @addr: IPv6 address
888c2ecf20Sopenharmony_ci * @head: the list head
898c2ecf20Sopenharmony_ci *
908c2ecf20Sopenharmony_ci * Description:
918c2ecf20Sopenharmony_ci * Searches the IPv6 address list given by @head.  If a matching address entry
928c2ecf20Sopenharmony_ci * is found it is returned, otherwise NULL is returned.  The caller is
938c2ecf20Sopenharmony_ci * responsible for calling the rcu_read_[un]lock() functions.
948c2ecf20Sopenharmony_ci *
958c2ecf20Sopenharmony_ci */
968c2ecf20Sopenharmony_cistruct netlbl_af6list *netlbl_af6list_search(const struct in6_addr *addr,
978c2ecf20Sopenharmony_ci					     struct list_head *head)
988c2ecf20Sopenharmony_ci{
998c2ecf20Sopenharmony_ci	struct netlbl_af6list *iter;
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci	list_for_each_entry_rcu(iter, head, list)
1028c2ecf20Sopenharmony_ci		if (iter->valid &&
1038c2ecf20Sopenharmony_ci		    ipv6_masked_addr_cmp(&iter->addr, &iter->mask, addr) == 0)
1048c2ecf20Sopenharmony_ci			return iter;
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci	return NULL;
1078c2ecf20Sopenharmony_ci}
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci/**
1108c2ecf20Sopenharmony_ci * netlbl_af6list_search_exact - Search for an exact IPv6 address entry
1118c2ecf20Sopenharmony_ci * @addr: IPv6 address
1128c2ecf20Sopenharmony_ci * @mask: IPv6 address mask
1138c2ecf20Sopenharmony_ci * @head: the list head
1148c2ecf20Sopenharmony_ci *
1158c2ecf20Sopenharmony_ci * Description:
1168c2ecf20Sopenharmony_ci * Searches the IPv6 address list given by @head.  If an exact match if found
1178c2ecf20Sopenharmony_ci * it is returned, otherwise NULL is returned.  The caller is responsible for
1188c2ecf20Sopenharmony_ci * calling the rcu_read_[un]lock() functions.
1198c2ecf20Sopenharmony_ci *
1208c2ecf20Sopenharmony_ci */
1218c2ecf20Sopenharmony_cistruct netlbl_af6list *netlbl_af6list_search_exact(const struct in6_addr *addr,
1228c2ecf20Sopenharmony_ci						   const struct in6_addr *mask,
1238c2ecf20Sopenharmony_ci						   struct list_head *head)
1248c2ecf20Sopenharmony_ci{
1258c2ecf20Sopenharmony_ci	struct netlbl_af6list *iter;
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci	list_for_each_entry_rcu(iter, head, list)
1288c2ecf20Sopenharmony_ci		if (iter->valid &&
1298c2ecf20Sopenharmony_ci		    ipv6_addr_equal(&iter->addr, addr) &&
1308c2ecf20Sopenharmony_ci		    ipv6_addr_equal(&iter->mask, mask))
1318c2ecf20Sopenharmony_ci			return iter;
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci	return NULL;
1348c2ecf20Sopenharmony_ci}
1358c2ecf20Sopenharmony_ci#endif /* IPv6 */
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci/**
1388c2ecf20Sopenharmony_ci * netlbl_af4list_add - Add a new IPv4 address entry to a list
1398c2ecf20Sopenharmony_ci * @entry: address entry
1408c2ecf20Sopenharmony_ci * @head: the list head
1418c2ecf20Sopenharmony_ci *
1428c2ecf20Sopenharmony_ci * Description:
1438c2ecf20Sopenharmony_ci * Add a new address entry to the list pointed to by @head.  On success zero is
1448c2ecf20Sopenharmony_ci * returned, otherwise a negative value is returned.  The caller is responsible
1458c2ecf20Sopenharmony_ci * for calling the necessary locking functions.
1468c2ecf20Sopenharmony_ci *
1478c2ecf20Sopenharmony_ci */
1488c2ecf20Sopenharmony_ciint netlbl_af4list_add(struct netlbl_af4list *entry, struct list_head *head)
1498c2ecf20Sopenharmony_ci{
1508c2ecf20Sopenharmony_ci	struct netlbl_af4list *iter;
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci	iter = netlbl_af4list_search(entry->addr, head);
1538c2ecf20Sopenharmony_ci	if (iter != NULL &&
1548c2ecf20Sopenharmony_ci	    iter->addr == entry->addr && iter->mask == entry->mask)
1558c2ecf20Sopenharmony_ci		return -EEXIST;
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci	/* in order to speed up address searches through the list (the common
1588c2ecf20Sopenharmony_ci	 * case) we need to keep the list in order based on the size of the
1598c2ecf20Sopenharmony_ci	 * address mask such that the entry with the widest mask (smallest
1608c2ecf20Sopenharmony_ci	 * numerical value) appears first in the list */
1618c2ecf20Sopenharmony_ci	list_for_each_entry_rcu(iter, head, list)
1628c2ecf20Sopenharmony_ci		if (iter->valid &&
1638c2ecf20Sopenharmony_ci		    ntohl(entry->mask) > ntohl(iter->mask)) {
1648c2ecf20Sopenharmony_ci			__list_add_rcu(&entry->list,
1658c2ecf20Sopenharmony_ci				       iter->list.prev,
1668c2ecf20Sopenharmony_ci				       &iter->list);
1678c2ecf20Sopenharmony_ci			return 0;
1688c2ecf20Sopenharmony_ci		}
1698c2ecf20Sopenharmony_ci	list_add_tail_rcu(&entry->list, head);
1708c2ecf20Sopenharmony_ci	return 0;
1718c2ecf20Sopenharmony_ci}
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6)
1748c2ecf20Sopenharmony_ci/**
1758c2ecf20Sopenharmony_ci * netlbl_af6list_add - Add a new IPv6 address entry to a list
1768c2ecf20Sopenharmony_ci * @entry: address entry
1778c2ecf20Sopenharmony_ci * @head: the list head
1788c2ecf20Sopenharmony_ci *
1798c2ecf20Sopenharmony_ci * Description:
1808c2ecf20Sopenharmony_ci * Add a new address entry to the list pointed to by @head.  On success zero is
1818c2ecf20Sopenharmony_ci * returned, otherwise a negative value is returned.  The caller is responsible
1828c2ecf20Sopenharmony_ci * for calling the necessary locking functions.
1838c2ecf20Sopenharmony_ci *
1848c2ecf20Sopenharmony_ci */
1858c2ecf20Sopenharmony_ciint netlbl_af6list_add(struct netlbl_af6list *entry, struct list_head *head)
1868c2ecf20Sopenharmony_ci{
1878c2ecf20Sopenharmony_ci	struct netlbl_af6list *iter;
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci	iter = netlbl_af6list_search(&entry->addr, head);
1908c2ecf20Sopenharmony_ci	if (iter != NULL &&
1918c2ecf20Sopenharmony_ci	    ipv6_addr_equal(&iter->addr, &entry->addr) &&
1928c2ecf20Sopenharmony_ci	    ipv6_addr_equal(&iter->mask, &entry->mask))
1938c2ecf20Sopenharmony_ci		return -EEXIST;
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci	/* in order to speed up address searches through the list (the common
1968c2ecf20Sopenharmony_ci	 * case) we need to keep the list in order based on the size of the
1978c2ecf20Sopenharmony_ci	 * address mask such that the entry with the widest mask (smallest
1988c2ecf20Sopenharmony_ci	 * numerical value) appears first in the list */
1998c2ecf20Sopenharmony_ci	list_for_each_entry_rcu(iter, head, list)
2008c2ecf20Sopenharmony_ci		if (iter->valid &&
2018c2ecf20Sopenharmony_ci		    ipv6_addr_cmp(&entry->mask, &iter->mask) > 0) {
2028c2ecf20Sopenharmony_ci			__list_add_rcu(&entry->list,
2038c2ecf20Sopenharmony_ci				       iter->list.prev,
2048c2ecf20Sopenharmony_ci				       &iter->list);
2058c2ecf20Sopenharmony_ci			return 0;
2068c2ecf20Sopenharmony_ci		}
2078c2ecf20Sopenharmony_ci	list_add_tail_rcu(&entry->list, head);
2088c2ecf20Sopenharmony_ci	return 0;
2098c2ecf20Sopenharmony_ci}
2108c2ecf20Sopenharmony_ci#endif /* IPv6 */
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_ci/**
2138c2ecf20Sopenharmony_ci * netlbl_af4list_remove_entry - Remove an IPv4 address entry
2148c2ecf20Sopenharmony_ci * @entry: address entry
2158c2ecf20Sopenharmony_ci *
2168c2ecf20Sopenharmony_ci * Description:
2178c2ecf20Sopenharmony_ci * Remove the specified IP address entry.  The caller is responsible for
2188c2ecf20Sopenharmony_ci * calling the necessary locking functions.
2198c2ecf20Sopenharmony_ci *
2208c2ecf20Sopenharmony_ci */
2218c2ecf20Sopenharmony_civoid netlbl_af4list_remove_entry(struct netlbl_af4list *entry)
2228c2ecf20Sopenharmony_ci{
2238c2ecf20Sopenharmony_ci	entry->valid = 0;
2248c2ecf20Sopenharmony_ci	list_del_rcu(&entry->list);
2258c2ecf20Sopenharmony_ci}
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci/**
2288c2ecf20Sopenharmony_ci * netlbl_af4list_remove - Remove an IPv4 address entry
2298c2ecf20Sopenharmony_ci * @addr: IP address
2308c2ecf20Sopenharmony_ci * @mask: IP address mask
2318c2ecf20Sopenharmony_ci * @head: the list head
2328c2ecf20Sopenharmony_ci *
2338c2ecf20Sopenharmony_ci * Description:
2348c2ecf20Sopenharmony_ci * Remove an IP address entry from the list pointed to by @head.  Returns the
2358c2ecf20Sopenharmony_ci * entry on success, NULL on failure.  The caller is responsible for calling
2368c2ecf20Sopenharmony_ci * the necessary locking functions.
2378c2ecf20Sopenharmony_ci *
2388c2ecf20Sopenharmony_ci */
2398c2ecf20Sopenharmony_cistruct netlbl_af4list *netlbl_af4list_remove(__be32 addr, __be32 mask,
2408c2ecf20Sopenharmony_ci					     struct list_head *head)
2418c2ecf20Sopenharmony_ci{
2428c2ecf20Sopenharmony_ci	struct netlbl_af4list *entry;
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci	entry = netlbl_af4list_search_exact(addr, mask, head);
2458c2ecf20Sopenharmony_ci	if (entry == NULL)
2468c2ecf20Sopenharmony_ci		return NULL;
2478c2ecf20Sopenharmony_ci	netlbl_af4list_remove_entry(entry);
2488c2ecf20Sopenharmony_ci	return entry;
2498c2ecf20Sopenharmony_ci}
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6)
2528c2ecf20Sopenharmony_ci/**
2538c2ecf20Sopenharmony_ci * netlbl_af6list_remove_entry - Remove an IPv6 address entry
2548c2ecf20Sopenharmony_ci * @entry: address entry
2558c2ecf20Sopenharmony_ci *
2568c2ecf20Sopenharmony_ci * Description:
2578c2ecf20Sopenharmony_ci * Remove the specified IP address entry.  The caller is responsible for
2588c2ecf20Sopenharmony_ci * calling the necessary locking functions.
2598c2ecf20Sopenharmony_ci *
2608c2ecf20Sopenharmony_ci */
2618c2ecf20Sopenharmony_civoid netlbl_af6list_remove_entry(struct netlbl_af6list *entry)
2628c2ecf20Sopenharmony_ci{
2638c2ecf20Sopenharmony_ci	entry->valid = 0;
2648c2ecf20Sopenharmony_ci	list_del_rcu(&entry->list);
2658c2ecf20Sopenharmony_ci}
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci/**
2688c2ecf20Sopenharmony_ci * netlbl_af6list_remove - Remove an IPv6 address entry
2698c2ecf20Sopenharmony_ci * @addr: IP address
2708c2ecf20Sopenharmony_ci * @mask: IP address mask
2718c2ecf20Sopenharmony_ci * @head: the list head
2728c2ecf20Sopenharmony_ci *
2738c2ecf20Sopenharmony_ci * Description:
2748c2ecf20Sopenharmony_ci * Remove an IP address entry from the list pointed to by @head.  Returns the
2758c2ecf20Sopenharmony_ci * entry on success, NULL on failure.  The caller is responsible for calling
2768c2ecf20Sopenharmony_ci * the necessary locking functions.
2778c2ecf20Sopenharmony_ci *
2788c2ecf20Sopenharmony_ci */
2798c2ecf20Sopenharmony_cistruct netlbl_af6list *netlbl_af6list_remove(const struct in6_addr *addr,
2808c2ecf20Sopenharmony_ci					     const struct in6_addr *mask,
2818c2ecf20Sopenharmony_ci					     struct list_head *head)
2828c2ecf20Sopenharmony_ci{
2838c2ecf20Sopenharmony_ci	struct netlbl_af6list *entry;
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ci	entry = netlbl_af6list_search_exact(addr, mask, head);
2868c2ecf20Sopenharmony_ci	if (entry == NULL)
2878c2ecf20Sopenharmony_ci		return NULL;
2888c2ecf20Sopenharmony_ci	netlbl_af6list_remove_entry(entry);
2898c2ecf20Sopenharmony_ci	return entry;
2908c2ecf20Sopenharmony_ci}
2918c2ecf20Sopenharmony_ci#endif /* IPv6 */
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci/*
2948c2ecf20Sopenharmony_ci * Audit Helper Functions
2958c2ecf20Sopenharmony_ci */
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci#ifdef CONFIG_AUDIT
2988c2ecf20Sopenharmony_ci/**
2998c2ecf20Sopenharmony_ci * netlbl_af4list_audit_addr - Audit an IPv4 address
3008c2ecf20Sopenharmony_ci * @audit_buf: audit buffer
3018c2ecf20Sopenharmony_ci * @src: true if source address, false if destination
3028c2ecf20Sopenharmony_ci * @dev: network interface
3038c2ecf20Sopenharmony_ci * @addr: IP address
3048c2ecf20Sopenharmony_ci * @mask: IP address mask
3058c2ecf20Sopenharmony_ci *
3068c2ecf20Sopenharmony_ci * Description:
3078c2ecf20Sopenharmony_ci * Write the IPv4 address and address mask, if necessary, to @audit_buf.
3088c2ecf20Sopenharmony_ci *
3098c2ecf20Sopenharmony_ci */
3108c2ecf20Sopenharmony_civoid netlbl_af4list_audit_addr(struct audit_buffer *audit_buf,
3118c2ecf20Sopenharmony_ci					int src, const char *dev,
3128c2ecf20Sopenharmony_ci					__be32 addr, __be32 mask)
3138c2ecf20Sopenharmony_ci{
3148c2ecf20Sopenharmony_ci	u32 mask_val = ntohl(mask);
3158c2ecf20Sopenharmony_ci	char *dir = (src ? "src" : "dst");
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci	if (dev != NULL)
3188c2ecf20Sopenharmony_ci		audit_log_format(audit_buf, " netif=%s", dev);
3198c2ecf20Sopenharmony_ci	audit_log_format(audit_buf, " %s=%pI4", dir, &addr);
3208c2ecf20Sopenharmony_ci	if (mask_val != 0xffffffff) {
3218c2ecf20Sopenharmony_ci		u32 mask_len = 0;
3228c2ecf20Sopenharmony_ci		while (mask_val > 0) {
3238c2ecf20Sopenharmony_ci			mask_val <<= 1;
3248c2ecf20Sopenharmony_ci			mask_len++;
3258c2ecf20Sopenharmony_ci		}
3268c2ecf20Sopenharmony_ci		audit_log_format(audit_buf, " %s_prefixlen=%d", dir, mask_len);
3278c2ecf20Sopenharmony_ci	}
3288c2ecf20Sopenharmony_ci}
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6)
3318c2ecf20Sopenharmony_ci/**
3328c2ecf20Sopenharmony_ci * netlbl_af6list_audit_addr - Audit an IPv6 address
3338c2ecf20Sopenharmony_ci * @audit_buf: audit buffer
3348c2ecf20Sopenharmony_ci * @src: true if source address, false if destination
3358c2ecf20Sopenharmony_ci * @dev: network interface
3368c2ecf20Sopenharmony_ci * @addr: IP address
3378c2ecf20Sopenharmony_ci * @mask: IP address mask
3388c2ecf20Sopenharmony_ci *
3398c2ecf20Sopenharmony_ci * Description:
3408c2ecf20Sopenharmony_ci * Write the IPv6 address and address mask, if necessary, to @audit_buf.
3418c2ecf20Sopenharmony_ci *
3428c2ecf20Sopenharmony_ci */
3438c2ecf20Sopenharmony_civoid netlbl_af6list_audit_addr(struct audit_buffer *audit_buf,
3448c2ecf20Sopenharmony_ci				 int src,
3458c2ecf20Sopenharmony_ci				 const char *dev,
3468c2ecf20Sopenharmony_ci				 const struct in6_addr *addr,
3478c2ecf20Sopenharmony_ci				 const struct in6_addr *mask)
3488c2ecf20Sopenharmony_ci{
3498c2ecf20Sopenharmony_ci	char *dir = (src ? "src" : "dst");
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci	if (dev != NULL)
3528c2ecf20Sopenharmony_ci		audit_log_format(audit_buf, " netif=%s", dev);
3538c2ecf20Sopenharmony_ci	audit_log_format(audit_buf, " %s=%pI6", dir, addr);
3548c2ecf20Sopenharmony_ci	if (ntohl(mask->s6_addr32[3]) != 0xffffffff) {
3558c2ecf20Sopenharmony_ci		u32 mask_len = 0;
3568c2ecf20Sopenharmony_ci		u32 mask_val;
3578c2ecf20Sopenharmony_ci		int iter = -1;
3588c2ecf20Sopenharmony_ci		while (ntohl(mask->s6_addr32[++iter]) == 0xffffffff)
3598c2ecf20Sopenharmony_ci			mask_len += 32;
3608c2ecf20Sopenharmony_ci		mask_val = ntohl(mask->s6_addr32[iter]);
3618c2ecf20Sopenharmony_ci		while (mask_val > 0) {
3628c2ecf20Sopenharmony_ci			mask_val <<= 1;
3638c2ecf20Sopenharmony_ci			mask_len++;
3648c2ecf20Sopenharmony_ci		}
3658c2ecf20Sopenharmony_ci		audit_log_format(audit_buf, " %s_prefixlen=%d", dir, mask_len);
3668c2ecf20Sopenharmony_ci	}
3678c2ecf20Sopenharmony_ci}
3688c2ecf20Sopenharmony_ci#endif /* IPv6 */
3698c2ecf20Sopenharmony_ci#endif /* CONFIG_AUDIT */
370