18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *	Generic address resultion entity
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci *	Authors:
68c2ecf20Sopenharmony_ci *	net_random Alan Cox
78c2ecf20Sopenharmony_ci *	net_ratelimit Andi Kleen
88c2ecf20Sopenharmony_ci *	in{4,6}_pton YOSHIFUJI Hideaki, Copyright (C)2006 USAGI/WIDE Project
98c2ecf20Sopenharmony_ci *
108c2ecf20Sopenharmony_ci *	Created by Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
118c2ecf20Sopenharmony_ci */
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci#include <linux/module.h>
148c2ecf20Sopenharmony_ci#include <linux/jiffies.h>
158c2ecf20Sopenharmony_ci#include <linux/kernel.h>
168c2ecf20Sopenharmony_ci#include <linux/ctype.h>
178c2ecf20Sopenharmony_ci#include <linux/inet.h>
188c2ecf20Sopenharmony_ci#include <linux/mm.h>
198c2ecf20Sopenharmony_ci#include <linux/net.h>
208c2ecf20Sopenharmony_ci#include <linux/string.h>
218c2ecf20Sopenharmony_ci#include <linux/types.h>
228c2ecf20Sopenharmony_ci#include <linux/percpu.h>
238c2ecf20Sopenharmony_ci#include <linux/init.h>
248c2ecf20Sopenharmony_ci#include <linux/ratelimit.h>
258c2ecf20Sopenharmony_ci#include <linux/socket.h>
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci#include <net/sock.h>
288c2ecf20Sopenharmony_ci#include <net/net_ratelimit.h>
298c2ecf20Sopenharmony_ci#include <net/ipv6.h>
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci#include <asm/byteorder.h>
328c2ecf20Sopenharmony_ci#include <linux/uaccess.h>
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ciDEFINE_RATELIMIT_STATE(net_ratelimit_state, 5 * HZ, 10);
358c2ecf20Sopenharmony_ci/*
368c2ecf20Sopenharmony_ci * All net warning printk()s should be guarded by this function.
378c2ecf20Sopenharmony_ci */
388c2ecf20Sopenharmony_ciint net_ratelimit(void)
398c2ecf20Sopenharmony_ci{
408c2ecf20Sopenharmony_ci	return __ratelimit(&net_ratelimit_state);
418c2ecf20Sopenharmony_ci}
428c2ecf20Sopenharmony_ciEXPORT_SYMBOL(net_ratelimit);
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci/*
458c2ecf20Sopenharmony_ci * Convert an ASCII string to binary IP.
468c2ecf20Sopenharmony_ci * This is outside of net/ipv4/ because various code that uses IP addresses
478c2ecf20Sopenharmony_ci * is otherwise not dependent on the TCP/IP stack.
488c2ecf20Sopenharmony_ci */
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci__be32 in_aton(const char *str)
518c2ecf20Sopenharmony_ci{
528c2ecf20Sopenharmony_ci	unsigned int l;
538c2ecf20Sopenharmony_ci	unsigned int val;
548c2ecf20Sopenharmony_ci	int i;
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci	l = 0;
578c2ecf20Sopenharmony_ci	for (i = 0; i < 4; i++)	{
588c2ecf20Sopenharmony_ci		l <<= 8;
598c2ecf20Sopenharmony_ci		if (*str != '\0') {
608c2ecf20Sopenharmony_ci			val = 0;
618c2ecf20Sopenharmony_ci			while (*str != '\0' && *str != '.' && *str != '\n') {
628c2ecf20Sopenharmony_ci				val *= 10;
638c2ecf20Sopenharmony_ci				val += *str - '0';
648c2ecf20Sopenharmony_ci				str++;
658c2ecf20Sopenharmony_ci			}
668c2ecf20Sopenharmony_ci			l |= val;
678c2ecf20Sopenharmony_ci			if (*str != '\0')
688c2ecf20Sopenharmony_ci				str++;
698c2ecf20Sopenharmony_ci		}
708c2ecf20Sopenharmony_ci	}
718c2ecf20Sopenharmony_ci	return htonl(l);
728c2ecf20Sopenharmony_ci}
738c2ecf20Sopenharmony_ciEXPORT_SYMBOL(in_aton);
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci#define IN6PTON_XDIGIT		0x00010000
768c2ecf20Sopenharmony_ci#define IN6PTON_DIGIT		0x00020000
778c2ecf20Sopenharmony_ci#define IN6PTON_COLON_MASK	0x00700000
788c2ecf20Sopenharmony_ci#define IN6PTON_COLON_1		0x00100000	/* single : requested */
798c2ecf20Sopenharmony_ci#define IN6PTON_COLON_2		0x00200000	/* second : requested */
808c2ecf20Sopenharmony_ci#define IN6PTON_COLON_1_2	0x00400000	/* :: requested */
818c2ecf20Sopenharmony_ci#define IN6PTON_DOT		0x00800000	/* . */
828c2ecf20Sopenharmony_ci#define IN6PTON_DELIM		0x10000000
838c2ecf20Sopenharmony_ci#define IN6PTON_NULL		0x20000000	/* first/tail */
848c2ecf20Sopenharmony_ci#define IN6PTON_UNKNOWN		0x40000000
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_cistatic inline int xdigit2bin(char c, int delim)
878c2ecf20Sopenharmony_ci{
888c2ecf20Sopenharmony_ci	int val;
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci	if (c == delim || c == '\0')
918c2ecf20Sopenharmony_ci		return IN6PTON_DELIM;
928c2ecf20Sopenharmony_ci	if (c == ':')
938c2ecf20Sopenharmony_ci		return IN6PTON_COLON_MASK;
948c2ecf20Sopenharmony_ci	if (c == '.')
958c2ecf20Sopenharmony_ci		return IN6PTON_DOT;
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci	val = hex_to_bin(c);
988c2ecf20Sopenharmony_ci	if (val >= 0)
998c2ecf20Sopenharmony_ci		return val | IN6PTON_XDIGIT | (val < 10 ? IN6PTON_DIGIT : 0);
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci	if (delim == -1)
1028c2ecf20Sopenharmony_ci		return IN6PTON_DELIM;
1038c2ecf20Sopenharmony_ci	return IN6PTON_UNKNOWN;
1048c2ecf20Sopenharmony_ci}
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci/**
1078c2ecf20Sopenharmony_ci * in4_pton - convert an IPv4 address from literal to binary representation
1088c2ecf20Sopenharmony_ci * @src: the start of the IPv4 address string
1098c2ecf20Sopenharmony_ci * @srclen: the length of the string, -1 means strlen(src)
1108c2ecf20Sopenharmony_ci * @dst: the binary (u8[4] array) representation of the IPv4 address
1118c2ecf20Sopenharmony_ci * @delim: the delimiter of the IPv4 address in @src, -1 means no delimiter
1128c2ecf20Sopenharmony_ci * @end: A pointer to the end of the parsed string will be placed here
1138c2ecf20Sopenharmony_ci *
1148c2ecf20Sopenharmony_ci * Return one on success, return zero when any error occurs
1158c2ecf20Sopenharmony_ci * and @end will point to the end of the parsed string.
1168c2ecf20Sopenharmony_ci *
1178c2ecf20Sopenharmony_ci */
1188c2ecf20Sopenharmony_ciint in4_pton(const char *src, int srclen,
1198c2ecf20Sopenharmony_ci	     u8 *dst,
1208c2ecf20Sopenharmony_ci	     int delim, const char **end)
1218c2ecf20Sopenharmony_ci{
1228c2ecf20Sopenharmony_ci	const char *s;
1238c2ecf20Sopenharmony_ci	u8 *d;
1248c2ecf20Sopenharmony_ci	u8 dbuf[4];
1258c2ecf20Sopenharmony_ci	int ret = 0;
1268c2ecf20Sopenharmony_ci	int i;
1278c2ecf20Sopenharmony_ci	int w = 0;
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci	if (srclen < 0)
1308c2ecf20Sopenharmony_ci		srclen = strlen(src);
1318c2ecf20Sopenharmony_ci	s = src;
1328c2ecf20Sopenharmony_ci	d = dbuf;
1338c2ecf20Sopenharmony_ci	i = 0;
1348c2ecf20Sopenharmony_ci	while (1) {
1358c2ecf20Sopenharmony_ci		int c;
1368c2ecf20Sopenharmony_ci		c = xdigit2bin(srclen > 0 ? *s : '\0', delim);
1378c2ecf20Sopenharmony_ci		if (!(c & (IN6PTON_DIGIT | IN6PTON_DOT | IN6PTON_DELIM | IN6PTON_COLON_MASK))) {
1388c2ecf20Sopenharmony_ci			goto out;
1398c2ecf20Sopenharmony_ci		}
1408c2ecf20Sopenharmony_ci		if (c & (IN6PTON_DOT | IN6PTON_DELIM | IN6PTON_COLON_MASK)) {
1418c2ecf20Sopenharmony_ci			if (w == 0)
1428c2ecf20Sopenharmony_ci				goto out;
1438c2ecf20Sopenharmony_ci			*d++ = w & 0xff;
1448c2ecf20Sopenharmony_ci			w = 0;
1458c2ecf20Sopenharmony_ci			i++;
1468c2ecf20Sopenharmony_ci			if (c & (IN6PTON_DELIM | IN6PTON_COLON_MASK)) {
1478c2ecf20Sopenharmony_ci				if (i != 4)
1488c2ecf20Sopenharmony_ci					goto out;
1498c2ecf20Sopenharmony_ci				break;
1508c2ecf20Sopenharmony_ci			}
1518c2ecf20Sopenharmony_ci			goto cont;
1528c2ecf20Sopenharmony_ci		}
1538c2ecf20Sopenharmony_ci		w = (w * 10) + c;
1548c2ecf20Sopenharmony_ci		if ((w & 0xffff) > 255) {
1558c2ecf20Sopenharmony_ci			goto out;
1568c2ecf20Sopenharmony_ci		}
1578c2ecf20Sopenharmony_cicont:
1588c2ecf20Sopenharmony_ci		if (i >= 4)
1598c2ecf20Sopenharmony_ci			goto out;
1608c2ecf20Sopenharmony_ci		s++;
1618c2ecf20Sopenharmony_ci		srclen--;
1628c2ecf20Sopenharmony_ci	}
1638c2ecf20Sopenharmony_ci	ret = 1;
1648c2ecf20Sopenharmony_ci	memcpy(dst, dbuf, sizeof(dbuf));
1658c2ecf20Sopenharmony_ciout:
1668c2ecf20Sopenharmony_ci	if (end)
1678c2ecf20Sopenharmony_ci		*end = s;
1688c2ecf20Sopenharmony_ci	return ret;
1698c2ecf20Sopenharmony_ci}
1708c2ecf20Sopenharmony_ciEXPORT_SYMBOL(in4_pton);
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci/**
1738c2ecf20Sopenharmony_ci * in6_pton - convert an IPv6 address from literal to binary representation
1748c2ecf20Sopenharmony_ci * @src: the start of the IPv6 address string
1758c2ecf20Sopenharmony_ci * @srclen: the length of the string, -1 means strlen(src)
1768c2ecf20Sopenharmony_ci * @dst: the binary (u8[16] array) representation of the IPv6 address
1778c2ecf20Sopenharmony_ci * @delim: the delimiter of the IPv6 address in @src, -1 means no delimiter
1788c2ecf20Sopenharmony_ci * @end: A pointer to the end of the parsed string will be placed here
1798c2ecf20Sopenharmony_ci *
1808c2ecf20Sopenharmony_ci * Return one on success, return zero when any error occurs
1818c2ecf20Sopenharmony_ci * and @end will point to the end of the parsed string.
1828c2ecf20Sopenharmony_ci *
1838c2ecf20Sopenharmony_ci */
1848c2ecf20Sopenharmony_ciint in6_pton(const char *src, int srclen,
1858c2ecf20Sopenharmony_ci	     u8 *dst,
1868c2ecf20Sopenharmony_ci	     int delim, const char **end)
1878c2ecf20Sopenharmony_ci{
1888c2ecf20Sopenharmony_ci	const char *s, *tok = NULL;
1898c2ecf20Sopenharmony_ci	u8 *d, *dc = NULL;
1908c2ecf20Sopenharmony_ci	u8 dbuf[16];
1918c2ecf20Sopenharmony_ci	int ret = 0;
1928c2ecf20Sopenharmony_ci	int i;
1938c2ecf20Sopenharmony_ci	int state = IN6PTON_COLON_1_2 | IN6PTON_XDIGIT | IN6PTON_NULL;
1948c2ecf20Sopenharmony_ci	int w = 0;
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ci	memset(dbuf, 0, sizeof(dbuf));
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci	s = src;
1998c2ecf20Sopenharmony_ci	d = dbuf;
2008c2ecf20Sopenharmony_ci	if (srclen < 0)
2018c2ecf20Sopenharmony_ci		srclen = strlen(src);
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci	while (1) {
2048c2ecf20Sopenharmony_ci		int c;
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ci		c = xdigit2bin(srclen > 0 ? *s : '\0', delim);
2078c2ecf20Sopenharmony_ci		if (!(c & state))
2088c2ecf20Sopenharmony_ci			goto out;
2098c2ecf20Sopenharmony_ci		if (c & (IN6PTON_DELIM | IN6PTON_COLON_MASK)) {
2108c2ecf20Sopenharmony_ci			/* process one 16-bit word */
2118c2ecf20Sopenharmony_ci			if (!(state & IN6PTON_NULL)) {
2128c2ecf20Sopenharmony_ci				*d++ = (w >> 8) & 0xff;
2138c2ecf20Sopenharmony_ci				*d++ = w & 0xff;
2148c2ecf20Sopenharmony_ci			}
2158c2ecf20Sopenharmony_ci			w = 0;
2168c2ecf20Sopenharmony_ci			if (c & IN6PTON_DELIM) {
2178c2ecf20Sopenharmony_ci				/* We've processed last word */
2188c2ecf20Sopenharmony_ci				break;
2198c2ecf20Sopenharmony_ci			}
2208c2ecf20Sopenharmony_ci			/*
2218c2ecf20Sopenharmony_ci			 * COLON_1 => XDIGIT
2228c2ecf20Sopenharmony_ci			 * COLON_2 => XDIGIT|DELIM
2238c2ecf20Sopenharmony_ci			 * COLON_1_2 => COLON_2
2248c2ecf20Sopenharmony_ci			 */
2258c2ecf20Sopenharmony_ci			switch (state & IN6PTON_COLON_MASK) {
2268c2ecf20Sopenharmony_ci			case IN6PTON_COLON_2:
2278c2ecf20Sopenharmony_ci				dc = d;
2288c2ecf20Sopenharmony_ci				state = IN6PTON_XDIGIT | IN6PTON_DELIM;
2298c2ecf20Sopenharmony_ci				if (dc - dbuf >= sizeof(dbuf))
2308c2ecf20Sopenharmony_ci					state |= IN6PTON_NULL;
2318c2ecf20Sopenharmony_ci				break;
2328c2ecf20Sopenharmony_ci			case IN6PTON_COLON_1|IN6PTON_COLON_1_2:
2338c2ecf20Sopenharmony_ci				state = IN6PTON_XDIGIT | IN6PTON_COLON_2;
2348c2ecf20Sopenharmony_ci				break;
2358c2ecf20Sopenharmony_ci			case IN6PTON_COLON_1:
2368c2ecf20Sopenharmony_ci				state = IN6PTON_XDIGIT;
2378c2ecf20Sopenharmony_ci				break;
2388c2ecf20Sopenharmony_ci			case IN6PTON_COLON_1_2:
2398c2ecf20Sopenharmony_ci				state = IN6PTON_COLON_2;
2408c2ecf20Sopenharmony_ci				break;
2418c2ecf20Sopenharmony_ci			default:
2428c2ecf20Sopenharmony_ci				state = 0;
2438c2ecf20Sopenharmony_ci			}
2448c2ecf20Sopenharmony_ci			tok = s + 1;
2458c2ecf20Sopenharmony_ci			goto cont;
2468c2ecf20Sopenharmony_ci		}
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ci		if (c & IN6PTON_DOT) {
2498c2ecf20Sopenharmony_ci			ret = in4_pton(tok ? tok : s, srclen + (int)(s - tok), d, delim, &s);
2508c2ecf20Sopenharmony_ci			if (ret > 0) {
2518c2ecf20Sopenharmony_ci				d += 4;
2528c2ecf20Sopenharmony_ci				break;
2538c2ecf20Sopenharmony_ci			}
2548c2ecf20Sopenharmony_ci			goto out;
2558c2ecf20Sopenharmony_ci		}
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci		w = (w << 4) | (0xff & c);
2588c2ecf20Sopenharmony_ci		state = IN6PTON_COLON_1 | IN6PTON_DELIM;
2598c2ecf20Sopenharmony_ci		if (!(w & 0xf000)) {
2608c2ecf20Sopenharmony_ci			state |= IN6PTON_XDIGIT;
2618c2ecf20Sopenharmony_ci		}
2628c2ecf20Sopenharmony_ci		if (!dc && d + 2 < dbuf + sizeof(dbuf)) {
2638c2ecf20Sopenharmony_ci			state |= IN6PTON_COLON_1_2;
2648c2ecf20Sopenharmony_ci			state &= ~IN6PTON_DELIM;
2658c2ecf20Sopenharmony_ci		}
2668c2ecf20Sopenharmony_ci		if (d + 2 >= dbuf + sizeof(dbuf)) {
2678c2ecf20Sopenharmony_ci			state &= ~(IN6PTON_COLON_1|IN6PTON_COLON_1_2);
2688c2ecf20Sopenharmony_ci		}
2698c2ecf20Sopenharmony_cicont:
2708c2ecf20Sopenharmony_ci		if ((dc && d + 4 < dbuf + sizeof(dbuf)) ||
2718c2ecf20Sopenharmony_ci		    d + 4 == dbuf + sizeof(dbuf)) {
2728c2ecf20Sopenharmony_ci			state |= IN6PTON_DOT;
2738c2ecf20Sopenharmony_ci		}
2748c2ecf20Sopenharmony_ci		if (d >= dbuf + sizeof(dbuf)) {
2758c2ecf20Sopenharmony_ci			state &= ~(IN6PTON_XDIGIT|IN6PTON_COLON_MASK);
2768c2ecf20Sopenharmony_ci		}
2778c2ecf20Sopenharmony_ci		s++;
2788c2ecf20Sopenharmony_ci		srclen--;
2798c2ecf20Sopenharmony_ci	}
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ci	i = 15; d--;
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci	if (dc) {
2848c2ecf20Sopenharmony_ci		while (d >= dc)
2858c2ecf20Sopenharmony_ci			dst[i--] = *d--;
2868c2ecf20Sopenharmony_ci		while (i >= dc - dbuf)
2878c2ecf20Sopenharmony_ci			dst[i--] = 0;
2888c2ecf20Sopenharmony_ci		while (i >= 0)
2898c2ecf20Sopenharmony_ci			dst[i--] = *d--;
2908c2ecf20Sopenharmony_ci	} else
2918c2ecf20Sopenharmony_ci		memcpy(dst, dbuf, sizeof(dbuf));
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci	ret = 1;
2948c2ecf20Sopenharmony_ciout:
2958c2ecf20Sopenharmony_ci	if (end)
2968c2ecf20Sopenharmony_ci		*end = s;
2978c2ecf20Sopenharmony_ci	return ret;
2988c2ecf20Sopenharmony_ci}
2998c2ecf20Sopenharmony_ciEXPORT_SYMBOL(in6_pton);
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_cistatic int inet4_pton(const char *src, u16 port_num,
3028c2ecf20Sopenharmony_ci		struct sockaddr_storage *addr)
3038c2ecf20Sopenharmony_ci{
3048c2ecf20Sopenharmony_ci	struct sockaddr_in *addr4 = (struct sockaddr_in *)addr;
3058c2ecf20Sopenharmony_ci	int srclen = strlen(src);
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci	if (srclen > INET_ADDRSTRLEN)
3088c2ecf20Sopenharmony_ci		return -EINVAL;
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_ci	if (in4_pton(src, srclen, (u8 *)&addr4->sin_addr.s_addr,
3118c2ecf20Sopenharmony_ci		     '\n', NULL) == 0)
3128c2ecf20Sopenharmony_ci		return -EINVAL;
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci	addr4->sin_family = AF_INET;
3158c2ecf20Sopenharmony_ci	addr4->sin_port = htons(port_num);
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci	return 0;
3188c2ecf20Sopenharmony_ci}
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_cistatic int inet6_pton(struct net *net, const char *src, u16 port_num,
3218c2ecf20Sopenharmony_ci		struct sockaddr_storage *addr)
3228c2ecf20Sopenharmony_ci{
3238c2ecf20Sopenharmony_ci	struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)addr;
3248c2ecf20Sopenharmony_ci	const char *scope_delim;
3258c2ecf20Sopenharmony_ci	int srclen = strlen(src);
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_ci	if (srclen > INET6_ADDRSTRLEN)
3288c2ecf20Sopenharmony_ci		return -EINVAL;
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_ci	if (in6_pton(src, srclen, (u8 *)&addr6->sin6_addr.s6_addr,
3318c2ecf20Sopenharmony_ci		     '%', &scope_delim) == 0)
3328c2ecf20Sopenharmony_ci		return -EINVAL;
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci	if (ipv6_addr_type(&addr6->sin6_addr) & IPV6_ADDR_LINKLOCAL &&
3358c2ecf20Sopenharmony_ci	    src + srclen != scope_delim && *scope_delim == '%') {
3368c2ecf20Sopenharmony_ci		struct net_device *dev;
3378c2ecf20Sopenharmony_ci		char scope_id[16];
3388c2ecf20Sopenharmony_ci		size_t scope_len = min_t(size_t, sizeof(scope_id) - 1,
3398c2ecf20Sopenharmony_ci					 src + srclen - scope_delim - 1);
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_ci		memcpy(scope_id, scope_delim + 1, scope_len);
3428c2ecf20Sopenharmony_ci		scope_id[scope_len] = '\0';
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_ci		dev = dev_get_by_name(net, scope_id);
3458c2ecf20Sopenharmony_ci		if (dev) {
3468c2ecf20Sopenharmony_ci			addr6->sin6_scope_id = dev->ifindex;
3478c2ecf20Sopenharmony_ci			dev_put(dev);
3488c2ecf20Sopenharmony_ci		} else if (kstrtouint(scope_id, 0, &addr6->sin6_scope_id)) {
3498c2ecf20Sopenharmony_ci			return -EINVAL;
3508c2ecf20Sopenharmony_ci		}
3518c2ecf20Sopenharmony_ci	}
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_ci	addr6->sin6_family = AF_INET6;
3548c2ecf20Sopenharmony_ci	addr6->sin6_port = htons(port_num);
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ci	return 0;
3578c2ecf20Sopenharmony_ci}
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_ci/**
3608c2ecf20Sopenharmony_ci * inet_pton_with_scope - convert an IPv4/IPv6 and port to socket address
3618c2ecf20Sopenharmony_ci * @net: net namespace (used for scope handling)
3628c2ecf20Sopenharmony_ci * @af: address family, AF_INET, AF_INET6 or AF_UNSPEC for either
3638c2ecf20Sopenharmony_ci * @src: the start of the address string
3648c2ecf20Sopenharmony_ci * @port: the start of the port string (or NULL for none)
3658c2ecf20Sopenharmony_ci * @addr: output socket address
3668c2ecf20Sopenharmony_ci *
3678c2ecf20Sopenharmony_ci * Return zero on success, return errno when any error occurs.
3688c2ecf20Sopenharmony_ci */
3698c2ecf20Sopenharmony_ciint inet_pton_with_scope(struct net *net, __kernel_sa_family_t af,
3708c2ecf20Sopenharmony_ci		const char *src, const char *port, struct sockaddr_storage *addr)
3718c2ecf20Sopenharmony_ci{
3728c2ecf20Sopenharmony_ci	u16 port_num;
3738c2ecf20Sopenharmony_ci	int ret = -EINVAL;
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ci	if (port) {
3768c2ecf20Sopenharmony_ci		if (kstrtou16(port, 0, &port_num))
3778c2ecf20Sopenharmony_ci			return -EINVAL;
3788c2ecf20Sopenharmony_ci	} else {
3798c2ecf20Sopenharmony_ci		port_num = 0;
3808c2ecf20Sopenharmony_ci	}
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_ci	switch (af) {
3838c2ecf20Sopenharmony_ci	case AF_INET:
3848c2ecf20Sopenharmony_ci		ret = inet4_pton(src, port_num, addr);
3858c2ecf20Sopenharmony_ci		break;
3868c2ecf20Sopenharmony_ci	case AF_INET6:
3878c2ecf20Sopenharmony_ci		ret = inet6_pton(net, src, port_num, addr);
3888c2ecf20Sopenharmony_ci		break;
3898c2ecf20Sopenharmony_ci	case AF_UNSPEC:
3908c2ecf20Sopenharmony_ci		ret = inet4_pton(src, port_num, addr);
3918c2ecf20Sopenharmony_ci		if (ret)
3928c2ecf20Sopenharmony_ci			ret = inet6_pton(net, src, port_num, addr);
3938c2ecf20Sopenharmony_ci		break;
3948c2ecf20Sopenharmony_ci	default:
3958c2ecf20Sopenharmony_ci		pr_err("unexpected address family %d\n", af);
3968c2ecf20Sopenharmony_ci	}
3978c2ecf20Sopenharmony_ci
3988c2ecf20Sopenharmony_ci	return ret;
3998c2ecf20Sopenharmony_ci}
4008c2ecf20Sopenharmony_ciEXPORT_SYMBOL(inet_pton_with_scope);
4018c2ecf20Sopenharmony_ci
4028c2ecf20Sopenharmony_cibool inet_addr_is_any(struct sockaddr *addr)
4038c2ecf20Sopenharmony_ci{
4048c2ecf20Sopenharmony_ci	if (addr->sa_family == AF_INET6) {
4058c2ecf20Sopenharmony_ci		struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)addr;
4068c2ecf20Sopenharmony_ci		const struct sockaddr_in6 in6_any =
4078c2ecf20Sopenharmony_ci			{ .sin6_addr = IN6ADDR_ANY_INIT };
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_ci		if (!memcmp(in6->sin6_addr.s6_addr,
4108c2ecf20Sopenharmony_ci			    in6_any.sin6_addr.s6_addr, 16))
4118c2ecf20Sopenharmony_ci			return true;
4128c2ecf20Sopenharmony_ci	} else if (addr->sa_family == AF_INET) {
4138c2ecf20Sopenharmony_ci		struct sockaddr_in *in = (struct sockaddr_in *)addr;
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_ci		if (in->sin_addr.s_addr == htonl(INADDR_ANY))
4168c2ecf20Sopenharmony_ci			return true;
4178c2ecf20Sopenharmony_ci	} else {
4188c2ecf20Sopenharmony_ci		pr_warn("unexpected address family %u\n", addr->sa_family);
4198c2ecf20Sopenharmony_ci	}
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_ci	return false;
4228c2ecf20Sopenharmony_ci}
4238c2ecf20Sopenharmony_ciEXPORT_SYMBOL(inet_addr_is_any);
4248c2ecf20Sopenharmony_ci
4258c2ecf20Sopenharmony_civoid inet_proto_csum_replace4(__sum16 *sum, struct sk_buff *skb,
4268c2ecf20Sopenharmony_ci			      __be32 from, __be32 to, bool pseudohdr)
4278c2ecf20Sopenharmony_ci{
4288c2ecf20Sopenharmony_ci	if (skb->ip_summed != CHECKSUM_PARTIAL) {
4298c2ecf20Sopenharmony_ci		csum_replace4(sum, from, to);
4308c2ecf20Sopenharmony_ci		if (skb->ip_summed == CHECKSUM_COMPLETE && pseudohdr)
4318c2ecf20Sopenharmony_ci			skb->csum = ~csum_add(csum_sub(~(skb->csum),
4328c2ecf20Sopenharmony_ci						       (__force __wsum)from),
4338c2ecf20Sopenharmony_ci					      (__force __wsum)to);
4348c2ecf20Sopenharmony_ci	} else if (pseudohdr)
4358c2ecf20Sopenharmony_ci		*sum = ~csum_fold(csum_add(csum_sub(csum_unfold(*sum),
4368c2ecf20Sopenharmony_ci						    (__force __wsum)from),
4378c2ecf20Sopenharmony_ci					   (__force __wsum)to));
4388c2ecf20Sopenharmony_ci}
4398c2ecf20Sopenharmony_ciEXPORT_SYMBOL(inet_proto_csum_replace4);
4408c2ecf20Sopenharmony_ci
4418c2ecf20Sopenharmony_ci/**
4428c2ecf20Sopenharmony_ci * inet_proto_csum_replace16 - update layer 4 header checksum field
4438c2ecf20Sopenharmony_ci * @sum: Layer 4 header checksum field
4448c2ecf20Sopenharmony_ci * @skb: sk_buff for the packet
4458c2ecf20Sopenharmony_ci * @from: old IPv6 address
4468c2ecf20Sopenharmony_ci * @to: new IPv6 address
4478c2ecf20Sopenharmony_ci * @pseudohdr: True if layer 4 header checksum includes pseudoheader
4488c2ecf20Sopenharmony_ci *
4498c2ecf20Sopenharmony_ci * Update layer 4 header as per the update in IPv6 src/dst address.
4508c2ecf20Sopenharmony_ci *
4518c2ecf20Sopenharmony_ci * There is no need to update skb->csum in this function, because update in two
4528c2ecf20Sopenharmony_ci * fields a.) IPv6 src/dst address and b.) L4 header checksum cancels each other
4538c2ecf20Sopenharmony_ci * for skb->csum calculation. Whereas inet_proto_csum_replace4 function needs to
4548c2ecf20Sopenharmony_ci * update skb->csum, because update in 3 fields a.) IPv4 src/dst address,
4558c2ecf20Sopenharmony_ci * b.) IPv4 Header checksum and c.) L4 header checksum results in same diff as
4568c2ecf20Sopenharmony_ci * L4 Header checksum for skb->csum calculation.
4578c2ecf20Sopenharmony_ci */
4588c2ecf20Sopenharmony_civoid inet_proto_csum_replace16(__sum16 *sum, struct sk_buff *skb,
4598c2ecf20Sopenharmony_ci			       const __be32 *from, const __be32 *to,
4608c2ecf20Sopenharmony_ci			       bool pseudohdr)
4618c2ecf20Sopenharmony_ci{
4628c2ecf20Sopenharmony_ci	__be32 diff[] = {
4638c2ecf20Sopenharmony_ci		~from[0], ~from[1], ~from[2], ~from[3],
4648c2ecf20Sopenharmony_ci		to[0], to[1], to[2], to[3],
4658c2ecf20Sopenharmony_ci	};
4668c2ecf20Sopenharmony_ci	if (skb->ip_summed != CHECKSUM_PARTIAL) {
4678c2ecf20Sopenharmony_ci		*sum = csum_fold(csum_partial(diff, sizeof(diff),
4688c2ecf20Sopenharmony_ci				 ~csum_unfold(*sum)));
4698c2ecf20Sopenharmony_ci	} else if (pseudohdr)
4708c2ecf20Sopenharmony_ci		*sum = ~csum_fold(csum_partial(diff, sizeof(diff),
4718c2ecf20Sopenharmony_ci				  csum_unfold(*sum)));
4728c2ecf20Sopenharmony_ci}
4738c2ecf20Sopenharmony_ciEXPORT_SYMBOL(inet_proto_csum_replace16);
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_civoid inet_proto_csum_replace_by_diff(__sum16 *sum, struct sk_buff *skb,
4768c2ecf20Sopenharmony_ci				     __wsum diff, bool pseudohdr)
4778c2ecf20Sopenharmony_ci{
4788c2ecf20Sopenharmony_ci	if (skb->ip_summed != CHECKSUM_PARTIAL) {
4798c2ecf20Sopenharmony_ci		*sum = csum_fold(csum_add(diff, ~csum_unfold(*sum)));
4808c2ecf20Sopenharmony_ci		if (skb->ip_summed == CHECKSUM_COMPLETE && pseudohdr)
4818c2ecf20Sopenharmony_ci			skb->csum = ~csum_add(diff, ~skb->csum);
4828c2ecf20Sopenharmony_ci	} else if (pseudohdr) {
4838c2ecf20Sopenharmony_ci		*sum = ~csum_fold(csum_add(diff, csum_unfold(*sum)));
4848c2ecf20Sopenharmony_ci	}
4858c2ecf20Sopenharmony_ci}
4868c2ecf20Sopenharmony_ciEXPORT_SYMBOL(inet_proto_csum_replace_by_diff);
487