xref: /OK3568_Linux_fs/kernel/net/core/utils.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  *	Generic address resultion entity
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  *	Authors:
6*4882a593Smuzhiyun  *	net_random Alan Cox
7*4882a593Smuzhiyun  *	net_ratelimit Andi Kleen
8*4882a593Smuzhiyun  *	in{4,6}_pton YOSHIFUJI Hideaki, Copyright (C)2006 USAGI/WIDE Project
9*4882a593Smuzhiyun  *
10*4882a593Smuzhiyun  *	Created by Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
11*4882a593Smuzhiyun  */
12*4882a593Smuzhiyun 
13*4882a593Smuzhiyun #include <linux/module.h>
14*4882a593Smuzhiyun #include <linux/jiffies.h>
15*4882a593Smuzhiyun #include <linux/kernel.h>
16*4882a593Smuzhiyun #include <linux/ctype.h>
17*4882a593Smuzhiyun #include <linux/inet.h>
18*4882a593Smuzhiyun #include <linux/mm.h>
19*4882a593Smuzhiyun #include <linux/net.h>
20*4882a593Smuzhiyun #include <linux/string.h>
21*4882a593Smuzhiyun #include <linux/types.h>
22*4882a593Smuzhiyun #include <linux/percpu.h>
23*4882a593Smuzhiyun #include <linux/init.h>
24*4882a593Smuzhiyun #include <linux/ratelimit.h>
25*4882a593Smuzhiyun #include <linux/socket.h>
26*4882a593Smuzhiyun 
27*4882a593Smuzhiyun #include <net/sock.h>
28*4882a593Smuzhiyun #include <net/net_ratelimit.h>
29*4882a593Smuzhiyun #include <net/ipv6.h>
30*4882a593Smuzhiyun 
31*4882a593Smuzhiyun #include <asm/byteorder.h>
32*4882a593Smuzhiyun #include <linux/uaccess.h>
33*4882a593Smuzhiyun 
34*4882a593Smuzhiyun DEFINE_RATELIMIT_STATE(net_ratelimit_state, 5 * HZ, 10);
35*4882a593Smuzhiyun /*
36*4882a593Smuzhiyun  * All net warning printk()s should be guarded by this function.
37*4882a593Smuzhiyun  */
net_ratelimit(void)38*4882a593Smuzhiyun int net_ratelimit(void)
39*4882a593Smuzhiyun {
40*4882a593Smuzhiyun 	return __ratelimit(&net_ratelimit_state);
41*4882a593Smuzhiyun }
42*4882a593Smuzhiyun EXPORT_SYMBOL(net_ratelimit);
43*4882a593Smuzhiyun 
44*4882a593Smuzhiyun /*
45*4882a593Smuzhiyun  * Convert an ASCII string to binary IP.
46*4882a593Smuzhiyun  * This is outside of net/ipv4/ because various code that uses IP addresses
47*4882a593Smuzhiyun  * is otherwise not dependent on the TCP/IP stack.
48*4882a593Smuzhiyun  */
49*4882a593Smuzhiyun 
in_aton(const char * str)50*4882a593Smuzhiyun __be32 in_aton(const char *str)
51*4882a593Smuzhiyun {
52*4882a593Smuzhiyun 	unsigned int l;
53*4882a593Smuzhiyun 	unsigned int val;
54*4882a593Smuzhiyun 	int i;
55*4882a593Smuzhiyun 
56*4882a593Smuzhiyun 	l = 0;
57*4882a593Smuzhiyun 	for (i = 0; i < 4; i++)	{
58*4882a593Smuzhiyun 		l <<= 8;
59*4882a593Smuzhiyun 		if (*str != '\0') {
60*4882a593Smuzhiyun 			val = 0;
61*4882a593Smuzhiyun 			while (*str != '\0' && *str != '.' && *str != '\n') {
62*4882a593Smuzhiyun 				val *= 10;
63*4882a593Smuzhiyun 				val += *str - '0';
64*4882a593Smuzhiyun 				str++;
65*4882a593Smuzhiyun 			}
66*4882a593Smuzhiyun 			l |= val;
67*4882a593Smuzhiyun 			if (*str != '\0')
68*4882a593Smuzhiyun 				str++;
69*4882a593Smuzhiyun 		}
70*4882a593Smuzhiyun 	}
71*4882a593Smuzhiyun 	return htonl(l);
72*4882a593Smuzhiyun }
73*4882a593Smuzhiyun EXPORT_SYMBOL(in_aton);
74*4882a593Smuzhiyun 
75*4882a593Smuzhiyun #define IN6PTON_XDIGIT		0x00010000
76*4882a593Smuzhiyun #define IN6PTON_DIGIT		0x00020000
77*4882a593Smuzhiyun #define IN6PTON_COLON_MASK	0x00700000
78*4882a593Smuzhiyun #define IN6PTON_COLON_1		0x00100000	/* single : requested */
79*4882a593Smuzhiyun #define IN6PTON_COLON_2		0x00200000	/* second : requested */
80*4882a593Smuzhiyun #define IN6PTON_COLON_1_2	0x00400000	/* :: requested */
81*4882a593Smuzhiyun #define IN6PTON_DOT		0x00800000	/* . */
82*4882a593Smuzhiyun #define IN6PTON_DELIM		0x10000000
83*4882a593Smuzhiyun #define IN6PTON_NULL		0x20000000	/* first/tail */
84*4882a593Smuzhiyun #define IN6PTON_UNKNOWN		0x40000000
85*4882a593Smuzhiyun 
xdigit2bin(char c,int delim)86*4882a593Smuzhiyun static inline int xdigit2bin(char c, int delim)
87*4882a593Smuzhiyun {
88*4882a593Smuzhiyun 	int val;
89*4882a593Smuzhiyun 
90*4882a593Smuzhiyun 	if (c == delim || c == '\0')
91*4882a593Smuzhiyun 		return IN6PTON_DELIM;
92*4882a593Smuzhiyun 	if (c == ':')
93*4882a593Smuzhiyun 		return IN6PTON_COLON_MASK;
94*4882a593Smuzhiyun 	if (c == '.')
95*4882a593Smuzhiyun 		return IN6PTON_DOT;
96*4882a593Smuzhiyun 
97*4882a593Smuzhiyun 	val = hex_to_bin(c);
98*4882a593Smuzhiyun 	if (val >= 0)
99*4882a593Smuzhiyun 		return val | IN6PTON_XDIGIT | (val < 10 ? IN6PTON_DIGIT : 0);
100*4882a593Smuzhiyun 
101*4882a593Smuzhiyun 	if (delim == -1)
102*4882a593Smuzhiyun 		return IN6PTON_DELIM;
103*4882a593Smuzhiyun 	return IN6PTON_UNKNOWN;
104*4882a593Smuzhiyun }
105*4882a593Smuzhiyun 
106*4882a593Smuzhiyun /**
107*4882a593Smuzhiyun  * in4_pton - convert an IPv4 address from literal to binary representation
108*4882a593Smuzhiyun  * @src: the start of the IPv4 address string
109*4882a593Smuzhiyun  * @srclen: the length of the string, -1 means strlen(src)
110*4882a593Smuzhiyun  * @dst: the binary (u8[4] array) representation of the IPv4 address
111*4882a593Smuzhiyun  * @delim: the delimiter of the IPv4 address in @src, -1 means no delimiter
112*4882a593Smuzhiyun  * @end: A pointer to the end of the parsed string will be placed here
113*4882a593Smuzhiyun  *
114*4882a593Smuzhiyun  * Return one on success, return zero when any error occurs
115*4882a593Smuzhiyun  * and @end will point to the end of the parsed string.
116*4882a593Smuzhiyun  *
117*4882a593Smuzhiyun  */
in4_pton(const char * src,int srclen,u8 * dst,int delim,const char ** end)118*4882a593Smuzhiyun int in4_pton(const char *src, int srclen,
119*4882a593Smuzhiyun 	     u8 *dst,
120*4882a593Smuzhiyun 	     int delim, const char **end)
121*4882a593Smuzhiyun {
122*4882a593Smuzhiyun 	const char *s;
123*4882a593Smuzhiyun 	u8 *d;
124*4882a593Smuzhiyun 	u8 dbuf[4];
125*4882a593Smuzhiyun 	int ret = 0;
126*4882a593Smuzhiyun 	int i;
127*4882a593Smuzhiyun 	int w = 0;
128*4882a593Smuzhiyun 
129*4882a593Smuzhiyun 	if (srclen < 0)
130*4882a593Smuzhiyun 		srclen = strlen(src);
131*4882a593Smuzhiyun 	s = src;
132*4882a593Smuzhiyun 	d = dbuf;
133*4882a593Smuzhiyun 	i = 0;
134*4882a593Smuzhiyun 	while (1) {
135*4882a593Smuzhiyun 		int c;
136*4882a593Smuzhiyun 		c = xdigit2bin(srclen > 0 ? *s : '\0', delim);
137*4882a593Smuzhiyun 		if (!(c & (IN6PTON_DIGIT | IN6PTON_DOT | IN6PTON_DELIM | IN6PTON_COLON_MASK))) {
138*4882a593Smuzhiyun 			goto out;
139*4882a593Smuzhiyun 		}
140*4882a593Smuzhiyun 		if (c & (IN6PTON_DOT | IN6PTON_DELIM | IN6PTON_COLON_MASK)) {
141*4882a593Smuzhiyun 			if (w == 0)
142*4882a593Smuzhiyun 				goto out;
143*4882a593Smuzhiyun 			*d++ = w & 0xff;
144*4882a593Smuzhiyun 			w = 0;
145*4882a593Smuzhiyun 			i++;
146*4882a593Smuzhiyun 			if (c & (IN6PTON_DELIM | IN6PTON_COLON_MASK)) {
147*4882a593Smuzhiyun 				if (i != 4)
148*4882a593Smuzhiyun 					goto out;
149*4882a593Smuzhiyun 				break;
150*4882a593Smuzhiyun 			}
151*4882a593Smuzhiyun 			goto cont;
152*4882a593Smuzhiyun 		}
153*4882a593Smuzhiyun 		w = (w * 10) + c;
154*4882a593Smuzhiyun 		if ((w & 0xffff) > 255) {
155*4882a593Smuzhiyun 			goto out;
156*4882a593Smuzhiyun 		}
157*4882a593Smuzhiyun cont:
158*4882a593Smuzhiyun 		if (i >= 4)
159*4882a593Smuzhiyun 			goto out;
160*4882a593Smuzhiyun 		s++;
161*4882a593Smuzhiyun 		srclen--;
162*4882a593Smuzhiyun 	}
163*4882a593Smuzhiyun 	ret = 1;
164*4882a593Smuzhiyun 	memcpy(dst, dbuf, sizeof(dbuf));
165*4882a593Smuzhiyun out:
166*4882a593Smuzhiyun 	if (end)
167*4882a593Smuzhiyun 		*end = s;
168*4882a593Smuzhiyun 	return ret;
169*4882a593Smuzhiyun }
170*4882a593Smuzhiyun EXPORT_SYMBOL(in4_pton);
171*4882a593Smuzhiyun 
172*4882a593Smuzhiyun /**
173*4882a593Smuzhiyun  * in6_pton - convert an IPv6 address from literal to binary representation
174*4882a593Smuzhiyun  * @src: the start of the IPv6 address string
175*4882a593Smuzhiyun  * @srclen: the length of the string, -1 means strlen(src)
176*4882a593Smuzhiyun  * @dst: the binary (u8[16] array) representation of the IPv6 address
177*4882a593Smuzhiyun  * @delim: the delimiter of the IPv6 address in @src, -1 means no delimiter
178*4882a593Smuzhiyun  * @end: A pointer to the end of the parsed string will be placed here
179*4882a593Smuzhiyun  *
180*4882a593Smuzhiyun  * Return one on success, return zero when any error occurs
181*4882a593Smuzhiyun  * and @end will point to the end of the parsed string.
182*4882a593Smuzhiyun  *
183*4882a593Smuzhiyun  */
in6_pton(const char * src,int srclen,u8 * dst,int delim,const char ** end)184*4882a593Smuzhiyun int in6_pton(const char *src, int srclen,
185*4882a593Smuzhiyun 	     u8 *dst,
186*4882a593Smuzhiyun 	     int delim, const char **end)
187*4882a593Smuzhiyun {
188*4882a593Smuzhiyun 	const char *s, *tok = NULL;
189*4882a593Smuzhiyun 	u8 *d, *dc = NULL;
190*4882a593Smuzhiyun 	u8 dbuf[16];
191*4882a593Smuzhiyun 	int ret = 0;
192*4882a593Smuzhiyun 	int i;
193*4882a593Smuzhiyun 	int state = IN6PTON_COLON_1_2 | IN6PTON_XDIGIT | IN6PTON_NULL;
194*4882a593Smuzhiyun 	int w = 0;
195*4882a593Smuzhiyun 
196*4882a593Smuzhiyun 	memset(dbuf, 0, sizeof(dbuf));
197*4882a593Smuzhiyun 
198*4882a593Smuzhiyun 	s = src;
199*4882a593Smuzhiyun 	d = dbuf;
200*4882a593Smuzhiyun 	if (srclen < 0)
201*4882a593Smuzhiyun 		srclen = strlen(src);
202*4882a593Smuzhiyun 
203*4882a593Smuzhiyun 	while (1) {
204*4882a593Smuzhiyun 		int c;
205*4882a593Smuzhiyun 
206*4882a593Smuzhiyun 		c = xdigit2bin(srclen > 0 ? *s : '\0', delim);
207*4882a593Smuzhiyun 		if (!(c & state))
208*4882a593Smuzhiyun 			goto out;
209*4882a593Smuzhiyun 		if (c & (IN6PTON_DELIM | IN6PTON_COLON_MASK)) {
210*4882a593Smuzhiyun 			/* process one 16-bit word */
211*4882a593Smuzhiyun 			if (!(state & IN6PTON_NULL)) {
212*4882a593Smuzhiyun 				*d++ = (w >> 8) & 0xff;
213*4882a593Smuzhiyun 				*d++ = w & 0xff;
214*4882a593Smuzhiyun 			}
215*4882a593Smuzhiyun 			w = 0;
216*4882a593Smuzhiyun 			if (c & IN6PTON_DELIM) {
217*4882a593Smuzhiyun 				/* We've processed last word */
218*4882a593Smuzhiyun 				break;
219*4882a593Smuzhiyun 			}
220*4882a593Smuzhiyun 			/*
221*4882a593Smuzhiyun 			 * COLON_1 => XDIGIT
222*4882a593Smuzhiyun 			 * COLON_2 => XDIGIT|DELIM
223*4882a593Smuzhiyun 			 * COLON_1_2 => COLON_2
224*4882a593Smuzhiyun 			 */
225*4882a593Smuzhiyun 			switch (state & IN6PTON_COLON_MASK) {
226*4882a593Smuzhiyun 			case IN6PTON_COLON_2:
227*4882a593Smuzhiyun 				dc = d;
228*4882a593Smuzhiyun 				state = IN6PTON_XDIGIT | IN6PTON_DELIM;
229*4882a593Smuzhiyun 				if (dc - dbuf >= sizeof(dbuf))
230*4882a593Smuzhiyun 					state |= IN6PTON_NULL;
231*4882a593Smuzhiyun 				break;
232*4882a593Smuzhiyun 			case IN6PTON_COLON_1|IN6PTON_COLON_1_2:
233*4882a593Smuzhiyun 				state = IN6PTON_XDIGIT | IN6PTON_COLON_2;
234*4882a593Smuzhiyun 				break;
235*4882a593Smuzhiyun 			case IN6PTON_COLON_1:
236*4882a593Smuzhiyun 				state = IN6PTON_XDIGIT;
237*4882a593Smuzhiyun 				break;
238*4882a593Smuzhiyun 			case IN6PTON_COLON_1_2:
239*4882a593Smuzhiyun 				state = IN6PTON_COLON_2;
240*4882a593Smuzhiyun 				break;
241*4882a593Smuzhiyun 			default:
242*4882a593Smuzhiyun 				state = 0;
243*4882a593Smuzhiyun 			}
244*4882a593Smuzhiyun 			tok = s + 1;
245*4882a593Smuzhiyun 			goto cont;
246*4882a593Smuzhiyun 		}
247*4882a593Smuzhiyun 
248*4882a593Smuzhiyun 		if (c & IN6PTON_DOT) {
249*4882a593Smuzhiyun 			ret = in4_pton(tok ? tok : s, srclen + (int)(s - tok), d, delim, &s);
250*4882a593Smuzhiyun 			if (ret > 0) {
251*4882a593Smuzhiyun 				d += 4;
252*4882a593Smuzhiyun 				break;
253*4882a593Smuzhiyun 			}
254*4882a593Smuzhiyun 			goto out;
255*4882a593Smuzhiyun 		}
256*4882a593Smuzhiyun 
257*4882a593Smuzhiyun 		w = (w << 4) | (0xff & c);
258*4882a593Smuzhiyun 		state = IN6PTON_COLON_1 | IN6PTON_DELIM;
259*4882a593Smuzhiyun 		if (!(w & 0xf000)) {
260*4882a593Smuzhiyun 			state |= IN6PTON_XDIGIT;
261*4882a593Smuzhiyun 		}
262*4882a593Smuzhiyun 		if (!dc && d + 2 < dbuf + sizeof(dbuf)) {
263*4882a593Smuzhiyun 			state |= IN6PTON_COLON_1_2;
264*4882a593Smuzhiyun 			state &= ~IN6PTON_DELIM;
265*4882a593Smuzhiyun 		}
266*4882a593Smuzhiyun 		if (d + 2 >= dbuf + sizeof(dbuf)) {
267*4882a593Smuzhiyun 			state &= ~(IN6PTON_COLON_1|IN6PTON_COLON_1_2);
268*4882a593Smuzhiyun 		}
269*4882a593Smuzhiyun cont:
270*4882a593Smuzhiyun 		if ((dc && d + 4 < dbuf + sizeof(dbuf)) ||
271*4882a593Smuzhiyun 		    d + 4 == dbuf + sizeof(dbuf)) {
272*4882a593Smuzhiyun 			state |= IN6PTON_DOT;
273*4882a593Smuzhiyun 		}
274*4882a593Smuzhiyun 		if (d >= dbuf + sizeof(dbuf)) {
275*4882a593Smuzhiyun 			state &= ~(IN6PTON_XDIGIT|IN6PTON_COLON_MASK);
276*4882a593Smuzhiyun 		}
277*4882a593Smuzhiyun 		s++;
278*4882a593Smuzhiyun 		srclen--;
279*4882a593Smuzhiyun 	}
280*4882a593Smuzhiyun 
281*4882a593Smuzhiyun 	i = 15; d--;
282*4882a593Smuzhiyun 
283*4882a593Smuzhiyun 	if (dc) {
284*4882a593Smuzhiyun 		while (d >= dc)
285*4882a593Smuzhiyun 			dst[i--] = *d--;
286*4882a593Smuzhiyun 		while (i >= dc - dbuf)
287*4882a593Smuzhiyun 			dst[i--] = 0;
288*4882a593Smuzhiyun 		while (i >= 0)
289*4882a593Smuzhiyun 			dst[i--] = *d--;
290*4882a593Smuzhiyun 	} else
291*4882a593Smuzhiyun 		memcpy(dst, dbuf, sizeof(dbuf));
292*4882a593Smuzhiyun 
293*4882a593Smuzhiyun 	ret = 1;
294*4882a593Smuzhiyun out:
295*4882a593Smuzhiyun 	if (end)
296*4882a593Smuzhiyun 		*end = s;
297*4882a593Smuzhiyun 	return ret;
298*4882a593Smuzhiyun }
299*4882a593Smuzhiyun EXPORT_SYMBOL(in6_pton);
300*4882a593Smuzhiyun 
inet4_pton(const char * src,u16 port_num,struct sockaddr_storage * addr)301*4882a593Smuzhiyun static int inet4_pton(const char *src, u16 port_num,
302*4882a593Smuzhiyun 		struct sockaddr_storage *addr)
303*4882a593Smuzhiyun {
304*4882a593Smuzhiyun 	struct sockaddr_in *addr4 = (struct sockaddr_in *)addr;
305*4882a593Smuzhiyun 	int srclen = strlen(src);
306*4882a593Smuzhiyun 
307*4882a593Smuzhiyun 	if (srclen > INET_ADDRSTRLEN)
308*4882a593Smuzhiyun 		return -EINVAL;
309*4882a593Smuzhiyun 
310*4882a593Smuzhiyun 	if (in4_pton(src, srclen, (u8 *)&addr4->sin_addr.s_addr,
311*4882a593Smuzhiyun 		     '\n', NULL) == 0)
312*4882a593Smuzhiyun 		return -EINVAL;
313*4882a593Smuzhiyun 
314*4882a593Smuzhiyun 	addr4->sin_family = AF_INET;
315*4882a593Smuzhiyun 	addr4->sin_port = htons(port_num);
316*4882a593Smuzhiyun 
317*4882a593Smuzhiyun 	return 0;
318*4882a593Smuzhiyun }
319*4882a593Smuzhiyun 
inet6_pton(struct net * net,const char * src,u16 port_num,struct sockaddr_storage * addr)320*4882a593Smuzhiyun static int inet6_pton(struct net *net, const char *src, u16 port_num,
321*4882a593Smuzhiyun 		struct sockaddr_storage *addr)
322*4882a593Smuzhiyun {
323*4882a593Smuzhiyun 	struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)addr;
324*4882a593Smuzhiyun 	const char *scope_delim;
325*4882a593Smuzhiyun 	int srclen = strlen(src);
326*4882a593Smuzhiyun 
327*4882a593Smuzhiyun 	if (srclen > INET6_ADDRSTRLEN)
328*4882a593Smuzhiyun 		return -EINVAL;
329*4882a593Smuzhiyun 
330*4882a593Smuzhiyun 	if (in6_pton(src, srclen, (u8 *)&addr6->sin6_addr.s6_addr,
331*4882a593Smuzhiyun 		     '%', &scope_delim) == 0)
332*4882a593Smuzhiyun 		return -EINVAL;
333*4882a593Smuzhiyun 
334*4882a593Smuzhiyun 	if (ipv6_addr_type(&addr6->sin6_addr) & IPV6_ADDR_LINKLOCAL &&
335*4882a593Smuzhiyun 	    src + srclen != scope_delim && *scope_delim == '%') {
336*4882a593Smuzhiyun 		struct net_device *dev;
337*4882a593Smuzhiyun 		char scope_id[16];
338*4882a593Smuzhiyun 		size_t scope_len = min_t(size_t, sizeof(scope_id) - 1,
339*4882a593Smuzhiyun 					 src + srclen - scope_delim - 1);
340*4882a593Smuzhiyun 
341*4882a593Smuzhiyun 		memcpy(scope_id, scope_delim + 1, scope_len);
342*4882a593Smuzhiyun 		scope_id[scope_len] = '\0';
343*4882a593Smuzhiyun 
344*4882a593Smuzhiyun 		dev = dev_get_by_name(net, scope_id);
345*4882a593Smuzhiyun 		if (dev) {
346*4882a593Smuzhiyun 			addr6->sin6_scope_id = dev->ifindex;
347*4882a593Smuzhiyun 			dev_put(dev);
348*4882a593Smuzhiyun 		} else if (kstrtouint(scope_id, 0, &addr6->sin6_scope_id)) {
349*4882a593Smuzhiyun 			return -EINVAL;
350*4882a593Smuzhiyun 		}
351*4882a593Smuzhiyun 	}
352*4882a593Smuzhiyun 
353*4882a593Smuzhiyun 	addr6->sin6_family = AF_INET6;
354*4882a593Smuzhiyun 	addr6->sin6_port = htons(port_num);
355*4882a593Smuzhiyun 
356*4882a593Smuzhiyun 	return 0;
357*4882a593Smuzhiyun }
358*4882a593Smuzhiyun 
359*4882a593Smuzhiyun /**
360*4882a593Smuzhiyun  * inet_pton_with_scope - convert an IPv4/IPv6 and port to socket address
361*4882a593Smuzhiyun  * @net: net namespace (used for scope handling)
362*4882a593Smuzhiyun  * @af: address family, AF_INET, AF_INET6 or AF_UNSPEC for either
363*4882a593Smuzhiyun  * @src: the start of the address string
364*4882a593Smuzhiyun  * @port: the start of the port string (or NULL for none)
365*4882a593Smuzhiyun  * @addr: output socket address
366*4882a593Smuzhiyun  *
367*4882a593Smuzhiyun  * Return zero on success, return errno when any error occurs.
368*4882a593Smuzhiyun  */
inet_pton_with_scope(struct net * net,__kernel_sa_family_t af,const char * src,const char * port,struct sockaddr_storage * addr)369*4882a593Smuzhiyun int inet_pton_with_scope(struct net *net, __kernel_sa_family_t af,
370*4882a593Smuzhiyun 		const char *src, const char *port, struct sockaddr_storage *addr)
371*4882a593Smuzhiyun {
372*4882a593Smuzhiyun 	u16 port_num;
373*4882a593Smuzhiyun 	int ret = -EINVAL;
374*4882a593Smuzhiyun 
375*4882a593Smuzhiyun 	if (port) {
376*4882a593Smuzhiyun 		if (kstrtou16(port, 0, &port_num))
377*4882a593Smuzhiyun 			return -EINVAL;
378*4882a593Smuzhiyun 	} else {
379*4882a593Smuzhiyun 		port_num = 0;
380*4882a593Smuzhiyun 	}
381*4882a593Smuzhiyun 
382*4882a593Smuzhiyun 	switch (af) {
383*4882a593Smuzhiyun 	case AF_INET:
384*4882a593Smuzhiyun 		ret = inet4_pton(src, port_num, addr);
385*4882a593Smuzhiyun 		break;
386*4882a593Smuzhiyun 	case AF_INET6:
387*4882a593Smuzhiyun 		ret = inet6_pton(net, src, port_num, addr);
388*4882a593Smuzhiyun 		break;
389*4882a593Smuzhiyun 	case AF_UNSPEC:
390*4882a593Smuzhiyun 		ret = inet4_pton(src, port_num, addr);
391*4882a593Smuzhiyun 		if (ret)
392*4882a593Smuzhiyun 			ret = inet6_pton(net, src, port_num, addr);
393*4882a593Smuzhiyun 		break;
394*4882a593Smuzhiyun 	default:
395*4882a593Smuzhiyun 		pr_err("unexpected address family %d\n", af);
396*4882a593Smuzhiyun 	}
397*4882a593Smuzhiyun 
398*4882a593Smuzhiyun 	return ret;
399*4882a593Smuzhiyun }
400*4882a593Smuzhiyun EXPORT_SYMBOL(inet_pton_with_scope);
401*4882a593Smuzhiyun 
inet_addr_is_any(struct sockaddr * addr)402*4882a593Smuzhiyun bool inet_addr_is_any(struct sockaddr *addr)
403*4882a593Smuzhiyun {
404*4882a593Smuzhiyun 	if (addr->sa_family == AF_INET6) {
405*4882a593Smuzhiyun 		struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)addr;
406*4882a593Smuzhiyun 		const struct sockaddr_in6 in6_any =
407*4882a593Smuzhiyun 			{ .sin6_addr = IN6ADDR_ANY_INIT };
408*4882a593Smuzhiyun 
409*4882a593Smuzhiyun 		if (!memcmp(in6->sin6_addr.s6_addr,
410*4882a593Smuzhiyun 			    in6_any.sin6_addr.s6_addr, 16))
411*4882a593Smuzhiyun 			return true;
412*4882a593Smuzhiyun 	} else if (addr->sa_family == AF_INET) {
413*4882a593Smuzhiyun 		struct sockaddr_in *in = (struct sockaddr_in *)addr;
414*4882a593Smuzhiyun 
415*4882a593Smuzhiyun 		if (in->sin_addr.s_addr == htonl(INADDR_ANY))
416*4882a593Smuzhiyun 			return true;
417*4882a593Smuzhiyun 	} else {
418*4882a593Smuzhiyun 		pr_warn("unexpected address family %u\n", addr->sa_family);
419*4882a593Smuzhiyun 	}
420*4882a593Smuzhiyun 
421*4882a593Smuzhiyun 	return false;
422*4882a593Smuzhiyun }
423*4882a593Smuzhiyun EXPORT_SYMBOL(inet_addr_is_any);
424*4882a593Smuzhiyun 
inet_proto_csum_replace4(__sum16 * sum,struct sk_buff * skb,__be32 from,__be32 to,bool pseudohdr)425*4882a593Smuzhiyun void inet_proto_csum_replace4(__sum16 *sum, struct sk_buff *skb,
426*4882a593Smuzhiyun 			      __be32 from, __be32 to, bool pseudohdr)
427*4882a593Smuzhiyun {
428*4882a593Smuzhiyun 	if (skb->ip_summed != CHECKSUM_PARTIAL) {
429*4882a593Smuzhiyun 		csum_replace4(sum, from, to);
430*4882a593Smuzhiyun 		if (skb->ip_summed == CHECKSUM_COMPLETE && pseudohdr)
431*4882a593Smuzhiyun 			skb->csum = ~csum_add(csum_sub(~(skb->csum),
432*4882a593Smuzhiyun 						       (__force __wsum)from),
433*4882a593Smuzhiyun 					      (__force __wsum)to);
434*4882a593Smuzhiyun 	} else if (pseudohdr)
435*4882a593Smuzhiyun 		*sum = ~csum_fold(csum_add(csum_sub(csum_unfold(*sum),
436*4882a593Smuzhiyun 						    (__force __wsum)from),
437*4882a593Smuzhiyun 					   (__force __wsum)to));
438*4882a593Smuzhiyun }
439*4882a593Smuzhiyun EXPORT_SYMBOL(inet_proto_csum_replace4);
440*4882a593Smuzhiyun 
441*4882a593Smuzhiyun /**
442*4882a593Smuzhiyun  * inet_proto_csum_replace16 - update layer 4 header checksum field
443*4882a593Smuzhiyun  * @sum: Layer 4 header checksum field
444*4882a593Smuzhiyun  * @skb: sk_buff for the packet
445*4882a593Smuzhiyun  * @from: old IPv6 address
446*4882a593Smuzhiyun  * @to: new IPv6 address
447*4882a593Smuzhiyun  * @pseudohdr: True if layer 4 header checksum includes pseudoheader
448*4882a593Smuzhiyun  *
449*4882a593Smuzhiyun  * Update layer 4 header as per the update in IPv6 src/dst address.
450*4882a593Smuzhiyun  *
451*4882a593Smuzhiyun  * There is no need to update skb->csum in this function, because update in two
452*4882a593Smuzhiyun  * fields a.) IPv6 src/dst address and b.) L4 header checksum cancels each other
453*4882a593Smuzhiyun  * for skb->csum calculation. Whereas inet_proto_csum_replace4 function needs to
454*4882a593Smuzhiyun  * update skb->csum, because update in 3 fields a.) IPv4 src/dst address,
455*4882a593Smuzhiyun  * b.) IPv4 Header checksum and c.) L4 header checksum results in same diff as
456*4882a593Smuzhiyun  * L4 Header checksum for skb->csum calculation.
457*4882a593Smuzhiyun  */
inet_proto_csum_replace16(__sum16 * sum,struct sk_buff * skb,const __be32 * from,const __be32 * to,bool pseudohdr)458*4882a593Smuzhiyun void inet_proto_csum_replace16(__sum16 *sum, struct sk_buff *skb,
459*4882a593Smuzhiyun 			       const __be32 *from, const __be32 *to,
460*4882a593Smuzhiyun 			       bool pseudohdr)
461*4882a593Smuzhiyun {
462*4882a593Smuzhiyun 	__be32 diff[] = {
463*4882a593Smuzhiyun 		~from[0], ~from[1], ~from[2], ~from[3],
464*4882a593Smuzhiyun 		to[0], to[1], to[2], to[3],
465*4882a593Smuzhiyun 	};
466*4882a593Smuzhiyun 	if (skb->ip_summed != CHECKSUM_PARTIAL) {
467*4882a593Smuzhiyun 		*sum = csum_fold(csum_partial(diff, sizeof(diff),
468*4882a593Smuzhiyun 				 ~csum_unfold(*sum)));
469*4882a593Smuzhiyun 	} else if (pseudohdr)
470*4882a593Smuzhiyun 		*sum = ~csum_fold(csum_partial(diff, sizeof(diff),
471*4882a593Smuzhiyun 				  csum_unfold(*sum)));
472*4882a593Smuzhiyun }
473*4882a593Smuzhiyun EXPORT_SYMBOL(inet_proto_csum_replace16);
474*4882a593Smuzhiyun 
inet_proto_csum_replace_by_diff(__sum16 * sum,struct sk_buff * skb,__wsum diff,bool pseudohdr)475*4882a593Smuzhiyun void inet_proto_csum_replace_by_diff(__sum16 *sum, struct sk_buff *skb,
476*4882a593Smuzhiyun 				     __wsum diff, bool pseudohdr)
477*4882a593Smuzhiyun {
478*4882a593Smuzhiyun 	if (skb->ip_summed != CHECKSUM_PARTIAL) {
479*4882a593Smuzhiyun 		*sum = csum_fold(csum_add(diff, ~csum_unfold(*sum)));
480*4882a593Smuzhiyun 		if (skb->ip_summed == CHECKSUM_COMPLETE && pseudohdr)
481*4882a593Smuzhiyun 			skb->csum = ~csum_add(diff, ~skb->csum);
482*4882a593Smuzhiyun 	} else if (pseudohdr) {
483*4882a593Smuzhiyun 		*sum = ~csum_fold(csum_add(diff, csum_unfold(*sum)));
484*4882a593Smuzhiyun 	}
485*4882a593Smuzhiyun }
486*4882a593Smuzhiyun EXPORT_SYMBOL(inet_proto_csum_replace_by_diff);
487