mirror of
				https://github.com/smaeul/u-boot.git
				synced 2025-11-04 05:50:17 +00:00 
			
		
		
		
	The function string_to_ip is already in net_utils, which is compiled unconditionally, but ip_to_string is currently only accessible if the legacy network stack is selected. This commit puts ip_to_string in net_utils.c and removes it from the legacy network code. Signed-off-by: Adriano Cordova <adrianox@gmail.com> Reviewed-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
		
			
				
	
	
		
			228 lines
		
	
	
		
			4.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			228 lines
		
	
	
		
			4.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
// SPDX-License-Identifier: GPL-2.0+
 | 
						|
/*
 | 
						|
 * Generic network code. Moved from net.c
 | 
						|
 *
 | 
						|
 * Copyright 1994 - 2000 Neil Russell.
 | 
						|
 * Copyright 2000 Roland Borde
 | 
						|
 * Copyright 2000 Paolo Scaffardi
 | 
						|
 * Copyright 2000-2002 Wolfgang Denk, wd@denx.de
 | 
						|
 * Copyright 2009 Dirk Behme, dirk.behme@googlemail.com
 | 
						|
 */
 | 
						|
 | 
						|
#include <net.h>
 | 
						|
#include <net6.h>
 | 
						|
#include <vsprintf.h>
 | 
						|
 | 
						|
struct in_addr string_to_ip(const char *s)
 | 
						|
{
 | 
						|
	struct in_addr addr;
 | 
						|
	char *e;
 | 
						|
	int i;
 | 
						|
 | 
						|
	addr.s_addr = 0;
 | 
						|
	if (s == NULL)
 | 
						|
		return addr;
 | 
						|
 | 
						|
	for (addr.s_addr = 0, i = 0; i < 4; ++i) {
 | 
						|
		ulong val = s ? dectoul(s, &e) : 0;
 | 
						|
		if (val > 255) {
 | 
						|
			addr.s_addr = 0;
 | 
						|
			return addr;
 | 
						|
		}
 | 
						|
		if (i != 3 && *e != '.') {
 | 
						|
			addr.s_addr = 0;
 | 
						|
			return addr;
 | 
						|
		}
 | 
						|
		addr.s_addr <<= 8;
 | 
						|
		addr.s_addr |= (val & 0xFF);
 | 
						|
		if (s) {
 | 
						|
			s = (*e) ? e+1 : e;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	addr.s_addr = htonl(addr.s_addr);
 | 
						|
	return addr;
 | 
						|
}
 | 
						|
 | 
						|
#if IS_ENABLED(CONFIG_IPV6)
 | 
						|
int string_to_ip6(const char *str, size_t len, struct in6_addr *addr)
 | 
						|
{
 | 
						|
	int colon_count = 0;
 | 
						|
	int found_double_colon = 0;
 | 
						|
	int xstart = 0;		/* first zero (double colon) */
 | 
						|
	int section_num = 7;	/* num words the double colon represents */
 | 
						|
	int i;
 | 
						|
	const char *s = str;
 | 
						|
	const char *const e = s + len;
 | 
						|
	struct in_addr zero_ip = {.s_addr = 0};
 | 
						|
 | 
						|
	if (!str)
 | 
						|
		return -1;
 | 
						|
 | 
						|
	/* First pass, verify the syntax and locate the double colon */
 | 
						|
	while (s < e) {
 | 
						|
		while (s < e && isxdigit((int)*s))
 | 
						|
			s++;
 | 
						|
		if (*s == '\0')
 | 
						|
			break;
 | 
						|
		if (*s != ':') {
 | 
						|
			if (*s == '.' && section_num >= 2) {
 | 
						|
				struct in_addr v4;
 | 
						|
 | 
						|
				while (s != str && *(s - 1) != ':')
 | 
						|
					--s;
 | 
						|
				v4 = string_to_ip(s);
 | 
						|
				if (memcmp(&zero_ip, &v4,
 | 
						|
					   sizeof(struct in_addr)) != 0) {
 | 
						|
					section_num -= 2;
 | 
						|
					break;
 | 
						|
				}
 | 
						|
			}
 | 
						|
			/* This could be a valid address */
 | 
						|
			break;
 | 
						|
		}
 | 
						|
		if (s == str) {
 | 
						|
			/* The address begins with a colon */
 | 
						|
			if (*++s != ':')
 | 
						|
				/* Must start with a double colon or a number */
 | 
						|
				goto out_err;
 | 
						|
		} else {
 | 
						|
			s++;
 | 
						|
			if (found_double_colon)
 | 
						|
				section_num--;
 | 
						|
			else
 | 
						|
				xstart++;
 | 
						|
		}
 | 
						|
 | 
						|
		if (*s == ':') {
 | 
						|
			if (found_double_colon)
 | 
						|
				/* Two double colons are not allowed */
 | 
						|
				goto out_err;
 | 
						|
			found_double_colon = 1;
 | 
						|
			section_num -= xstart;
 | 
						|
			s++;
 | 
						|
		}
 | 
						|
 | 
						|
		if (++colon_count == 7)
 | 
						|
			/* Found all colons */
 | 
						|
			break;
 | 
						|
		++s;
 | 
						|
	}
 | 
						|
 | 
						|
	if (colon_count == 0)
 | 
						|
		goto out_err;
 | 
						|
	if (*--s == ':')
 | 
						|
		section_num++;
 | 
						|
 | 
						|
	/* Second pass, read the address */
 | 
						|
	s = str;
 | 
						|
	for (i = 0; i < 8; i++) {
 | 
						|
		int val = 0;
 | 
						|
		char *end;
 | 
						|
 | 
						|
		if (found_double_colon &&
 | 
						|
		    i >= xstart && i < xstart + section_num) {
 | 
						|
			addr->s6_addr16[i] = 0;
 | 
						|
			continue;
 | 
						|
		}
 | 
						|
		while (*s == ':')
 | 
						|
			s++;
 | 
						|
 | 
						|
		if (i == 6 && isdigit((int)*s)) {
 | 
						|
			struct in_addr v4 = string_to_ip(s);
 | 
						|
 | 
						|
			if (memcmp(&zero_ip, &v4,
 | 
						|
				   sizeof(struct in_addr)) != 0) {
 | 
						|
				/* Ending with :IPv4-address */
 | 
						|
				addr->s6_addr32[3] = v4.s_addr;
 | 
						|
				break;
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		val = simple_strtoul(s, &end, 16);
 | 
						|
		if (end != e && *end != '\0' && *end != ':')
 | 
						|
			goto out_err;
 | 
						|
		addr->s6_addr16[i] = htons(val);
 | 
						|
		s = end;
 | 
						|
	}
 | 
						|
	return 0;
 | 
						|
 | 
						|
out_err:
 | 
						|
	return -1;
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
void ip_to_string(struct in_addr x, char *s)
 | 
						|
{
 | 
						|
	x.s_addr = ntohl(x.s_addr);
 | 
						|
	sprintf(s, "%d.%d.%d.%d",
 | 
						|
		(int) ((x.s_addr >> 24) & 0xff),
 | 
						|
		(int) ((x.s_addr >> 16) & 0xff),
 | 
						|
		(int) ((x.s_addr >> 8) & 0xff),
 | 
						|
		(int) ((x.s_addr >> 0) & 0xff)
 | 
						|
	);
 | 
						|
}
 | 
						|
 | 
						|
void string_to_enetaddr(const char *addr, uint8_t *enetaddr)
 | 
						|
{
 | 
						|
	char *end;
 | 
						|
	int i;
 | 
						|
 | 
						|
	if (!enetaddr)
 | 
						|
		return;
 | 
						|
 | 
						|
	for (i = 0; i < 6; ++i) {
 | 
						|
		enetaddr[i] = addr ? hextoul(addr, &end) : 0;
 | 
						|
		if (addr)
 | 
						|
			addr = (*end) ? end + 1 : end;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
uint compute_ip_checksum(const void *vptr, uint nbytes)
 | 
						|
{
 | 
						|
	int sum, oddbyte;
 | 
						|
	const unsigned short *ptr = vptr;
 | 
						|
 | 
						|
	sum = 0;
 | 
						|
	while (nbytes > 1) {
 | 
						|
		sum += *ptr++;
 | 
						|
		nbytes -= 2;
 | 
						|
	}
 | 
						|
	if (nbytes == 1) {
 | 
						|
		oddbyte = 0;
 | 
						|
		((u8 *)&oddbyte)[0] = *(u8 *)ptr;
 | 
						|
		((u8 *)&oddbyte)[1] = 0;
 | 
						|
		sum += oddbyte;
 | 
						|
	}
 | 
						|
	sum = (sum >> 16) + (sum & 0xffff);
 | 
						|
	sum += (sum >> 16);
 | 
						|
	sum = ~sum & 0xffff;
 | 
						|
 | 
						|
	return sum;
 | 
						|
}
 | 
						|
 | 
						|
uint add_ip_checksums(uint offset, uint sum, uint new)
 | 
						|
{
 | 
						|
	ulong checksum;
 | 
						|
 | 
						|
	sum = ~sum & 0xffff;
 | 
						|
	new = ~new & 0xffff;
 | 
						|
	if (offset & 1) {
 | 
						|
		/*
 | 
						|
		 * byte-swap the sum if it came from an odd offset; since the
 | 
						|
		 * computation is endian-independent this works.
 | 
						|
		 */
 | 
						|
		new = ((new >> 8) & 0xff) | ((new << 8) & 0xff00);
 | 
						|
	}
 | 
						|
	checksum = sum + new;
 | 
						|
	if (checksum > 0xffff)
 | 
						|
		checksum -= 0xffff;
 | 
						|
 | 
						|
	return (~checksum) & 0xffff;
 | 
						|
}
 | 
						|
 | 
						|
int ip_checksum_ok(const void *addr, uint nbytes)
 | 
						|
{
 | 
						|
	return !(compute_ip_checksum(addr, nbytes) & 0xfffe);
 | 
						|
}
 |