162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * linux/include/linux/sunrpc/addr.h
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Various routines for copying and comparing sockaddrs and for
662306a36Sopenharmony_ci * converting them to and from presentation format.
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci#ifndef _LINUX_SUNRPC_ADDR_H
962306a36Sopenharmony_ci#define _LINUX_SUNRPC_ADDR_H
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <linux/socket.h>
1262306a36Sopenharmony_ci#include <linux/in.h>
1362306a36Sopenharmony_ci#include <linux/in6.h>
1462306a36Sopenharmony_ci#include <net/ipv6.h>
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_cisize_t		rpc_ntop(const struct sockaddr *, char *, const size_t);
1762306a36Sopenharmony_cisize_t		rpc_pton(struct net *, const char *, const size_t,
1862306a36Sopenharmony_ci			 struct sockaddr *, const size_t);
1962306a36Sopenharmony_cichar *		rpc_sockaddr2uaddr(const struct sockaddr *, gfp_t);
2062306a36Sopenharmony_cisize_t		rpc_uaddr2sockaddr(struct net *, const char *, const size_t,
2162306a36Sopenharmony_ci				   struct sockaddr *, const size_t);
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_cistatic inline unsigned short rpc_get_port(const struct sockaddr *sap)
2462306a36Sopenharmony_ci{
2562306a36Sopenharmony_ci	switch (sap->sa_family) {
2662306a36Sopenharmony_ci	case AF_INET:
2762306a36Sopenharmony_ci		return ntohs(((struct sockaddr_in *)sap)->sin_port);
2862306a36Sopenharmony_ci	case AF_INET6:
2962306a36Sopenharmony_ci		return ntohs(((struct sockaddr_in6 *)sap)->sin6_port);
3062306a36Sopenharmony_ci	}
3162306a36Sopenharmony_ci	return 0;
3262306a36Sopenharmony_ci}
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_cistatic inline void rpc_set_port(struct sockaddr *sap,
3562306a36Sopenharmony_ci				const unsigned short port)
3662306a36Sopenharmony_ci{
3762306a36Sopenharmony_ci	switch (sap->sa_family) {
3862306a36Sopenharmony_ci	case AF_INET:
3962306a36Sopenharmony_ci		((struct sockaddr_in *)sap)->sin_port = htons(port);
4062306a36Sopenharmony_ci		break;
4162306a36Sopenharmony_ci	case AF_INET6:
4262306a36Sopenharmony_ci		((struct sockaddr_in6 *)sap)->sin6_port = htons(port);
4362306a36Sopenharmony_ci		break;
4462306a36Sopenharmony_ci	}
4562306a36Sopenharmony_ci}
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci#define IPV6_SCOPE_DELIMITER		'%'
4862306a36Sopenharmony_ci#define IPV6_SCOPE_ID_LEN		sizeof("%nnnnnnnnnn")
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_cistatic inline bool rpc_cmp_addr4(const struct sockaddr *sap1,
5162306a36Sopenharmony_ci				 const struct sockaddr *sap2)
5262306a36Sopenharmony_ci{
5362306a36Sopenharmony_ci	const struct sockaddr_in *sin1 = (const struct sockaddr_in *)sap1;
5462306a36Sopenharmony_ci	const struct sockaddr_in *sin2 = (const struct sockaddr_in *)sap2;
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci	return sin1->sin_addr.s_addr == sin2->sin_addr.s_addr;
5762306a36Sopenharmony_ci}
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_cistatic inline bool __rpc_copy_addr4(struct sockaddr *dst,
6062306a36Sopenharmony_ci				    const struct sockaddr *src)
6162306a36Sopenharmony_ci{
6262306a36Sopenharmony_ci	const struct sockaddr_in *ssin = (struct sockaddr_in *) src;
6362306a36Sopenharmony_ci	struct sockaddr_in *dsin = (struct sockaddr_in *) dst;
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci	dsin->sin_family = ssin->sin_family;
6662306a36Sopenharmony_ci	dsin->sin_addr.s_addr = ssin->sin_addr.s_addr;
6762306a36Sopenharmony_ci	return true;
6862306a36Sopenharmony_ci}
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6)
7162306a36Sopenharmony_cistatic inline bool rpc_cmp_addr6(const struct sockaddr *sap1,
7262306a36Sopenharmony_ci				 const struct sockaddr *sap2)
7362306a36Sopenharmony_ci{
7462306a36Sopenharmony_ci	const struct sockaddr_in6 *sin1 = (const struct sockaddr_in6 *)sap1;
7562306a36Sopenharmony_ci	const struct sockaddr_in6 *sin2 = (const struct sockaddr_in6 *)sap2;
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci	if (!ipv6_addr_equal(&sin1->sin6_addr, &sin2->sin6_addr))
7862306a36Sopenharmony_ci		return false;
7962306a36Sopenharmony_ci	else if (ipv6_addr_type(&sin1->sin6_addr) & IPV6_ADDR_LINKLOCAL)
8062306a36Sopenharmony_ci		return sin1->sin6_scope_id == sin2->sin6_scope_id;
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	return true;
8362306a36Sopenharmony_ci}
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_cistatic inline bool __rpc_copy_addr6(struct sockaddr *dst,
8662306a36Sopenharmony_ci				    const struct sockaddr *src)
8762306a36Sopenharmony_ci{
8862306a36Sopenharmony_ci	const struct sockaddr_in6 *ssin6 = (const struct sockaddr_in6 *) src;
8962306a36Sopenharmony_ci	struct sockaddr_in6 *dsin6 = (struct sockaddr_in6 *) dst;
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci	dsin6->sin6_family = ssin6->sin6_family;
9262306a36Sopenharmony_ci	dsin6->sin6_addr = ssin6->sin6_addr;
9362306a36Sopenharmony_ci	dsin6->sin6_scope_id = ssin6->sin6_scope_id;
9462306a36Sopenharmony_ci	return true;
9562306a36Sopenharmony_ci}
9662306a36Sopenharmony_ci#else	/* !(IS_ENABLED(CONFIG_IPV6) */
9762306a36Sopenharmony_cistatic inline bool rpc_cmp_addr6(const struct sockaddr *sap1,
9862306a36Sopenharmony_ci				   const struct sockaddr *sap2)
9962306a36Sopenharmony_ci{
10062306a36Sopenharmony_ci	return false;
10162306a36Sopenharmony_ci}
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_cistatic inline bool __rpc_copy_addr6(struct sockaddr *dst,
10462306a36Sopenharmony_ci				    const struct sockaddr *src)
10562306a36Sopenharmony_ci{
10662306a36Sopenharmony_ci	return false;
10762306a36Sopenharmony_ci}
10862306a36Sopenharmony_ci#endif	/* !(IS_ENABLED(CONFIG_IPV6) */
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci/**
11162306a36Sopenharmony_ci * rpc_cmp_addr - compare the address portion of two sockaddrs.
11262306a36Sopenharmony_ci * @sap1: first sockaddr
11362306a36Sopenharmony_ci * @sap2: second sockaddr
11462306a36Sopenharmony_ci *
11562306a36Sopenharmony_ci * Just compares the family and address portion. Ignores port, but
11662306a36Sopenharmony_ci * compares the scope if it's a link-local address.
11762306a36Sopenharmony_ci *
11862306a36Sopenharmony_ci * Returns true if the addrs are equal, false if they aren't.
11962306a36Sopenharmony_ci */
12062306a36Sopenharmony_cistatic inline bool rpc_cmp_addr(const struct sockaddr *sap1,
12162306a36Sopenharmony_ci				const struct sockaddr *sap2)
12262306a36Sopenharmony_ci{
12362306a36Sopenharmony_ci	if (sap1->sa_family == sap2->sa_family) {
12462306a36Sopenharmony_ci		switch (sap1->sa_family) {
12562306a36Sopenharmony_ci		case AF_INET:
12662306a36Sopenharmony_ci			return rpc_cmp_addr4(sap1, sap2);
12762306a36Sopenharmony_ci		case AF_INET6:
12862306a36Sopenharmony_ci			return rpc_cmp_addr6(sap1, sap2);
12962306a36Sopenharmony_ci		}
13062306a36Sopenharmony_ci	}
13162306a36Sopenharmony_ci	return false;
13262306a36Sopenharmony_ci}
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci/**
13562306a36Sopenharmony_ci * rpc_cmp_addr_port - compare the address and port number of two sockaddrs.
13662306a36Sopenharmony_ci * @sap1: first sockaddr
13762306a36Sopenharmony_ci * @sap2: second sockaddr
13862306a36Sopenharmony_ci */
13962306a36Sopenharmony_cistatic inline bool rpc_cmp_addr_port(const struct sockaddr *sap1,
14062306a36Sopenharmony_ci				     const struct sockaddr *sap2)
14162306a36Sopenharmony_ci{
14262306a36Sopenharmony_ci	if (!rpc_cmp_addr(sap1, sap2))
14362306a36Sopenharmony_ci		return false;
14462306a36Sopenharmony_ci	return rpc_get_port(sap1) == rpc_get_port(sap2);
14562306a36Sopenharmony_ci}
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci/**
14862306a36Sopenharmony_ci * rpc_copy_addr - copy the address portion of one sockaddr to another
14962306a36Sopenharmony_ci * @dst: destination sockaddr
15062306a36Sopenharmony_ci * @src: source sockaddr
15162306a36Sopenharmony_ci *
15262306a36Sopenharmony_ci * Just copies the address portion and family. Ignores port, scope, etc.
15362306a36Sopenharmony_ci * Caller is responsible for making certain that dst is large enough to hold
15462306a36Sopenharmony_ci * the address in src. Returns true if address family is supported. Returns
15562306a36Sopenharmony_ci * false otherwise.
15662306a36Sopenharmony_ci */
15762306a36Sopenharmony_cistatic inline bool rpc_copy_addr(struct sockaddr *dst,
15862306a36Sopenharmony_ci				 const struct sockaddr *src)
15962306a36Sopenharmony_ci{
16062306a36Sopenharmony_ci	switch (src->sa_family) {
16162306a36Sopenharmony_ci	case AF_INET:
16262306a36Sopenharmony_ci		return __rpc_copy_addr4(dst, src);
16362306a36Sopenharmony_ci	case AF_INET6:
16462306a36Sopenharmony_ci		return __rpc_copy_addr6(dst, src);
16562306a36Sopenharmony_ci	}
16662306a36Sopenharmony_ci	return false;
16762306a36Sopenharmony_ci}
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci/**
17062306a36Sopenharmony_ci * rpc_get_scope_id - return scopeid for a given sockaddr
17162306a36Sopenharmony_ci * @sa: sockaddr to get scopeid from
17262306a36Sopenharmony_ci *
17362306a36Sopenharmony_ci * Returns the value of the sin6_scope_id for AF_INET6 addrs, or 0 if
17462306a36Sopenharmony_ci * not an AF_INET6 address.
17562306a36Sopenharmony_ci */
17662306a36Sopenharmony_cistatic inline u32 rpc_get_scope_id(const struct sockaddr *sa)
17762306a36Sopenharmony_ci{
17862306a36Sopenharmony_ci	if (sa->sa_family != AF_INET6)
17962306a36Sopenharmony_ci		return 0;
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci	return ((struct sockaddr_in6 *) sa)->sin6_scope_id;
18262306a36Sopenharmony_ci}
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci#endif /* _LINUX_SUNRPC_ADDR_H */
185