1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Generic network code. Moved from net.c
4  *
5  * Copyright 1994 - 2000 Neil Russell.
6  * Copyright 2000 Roland Borde
7  * Copyright 2000 Paolo Scaffardi
8  * Copyright 2000-2002 Wolfgang Denk, wd@denx.de
9  * Copyright 2009 Dirk Behme, dirk.behme@googlemail.com
10  */
11 
12 #include <common.h>
13 #include <net.h>
14 
string_to_ip(const char * s)15 struct in_addr string_to_ip(const char *s)
16 {
17 	struct in_addr addr;
18 	char *e;
19 	int i;
20 
21 	addr.s_addr = 0;
22 	if (s == NULL)
23 		return addr;
24 
25 	for (addr.s_addr = 0, i = 0; i < 4; ++i) {
26 		ulong val = s ? simple_strtoul(s, &e, 10) : 0;
27 		if (val > 255) {
28 			addr.s_addr = 0;
29 			return addr;
30 		}
31 		if (i != 3 && *e != '.') {
32 			addr.s_addr = 0;
33 			return addr;
34 		}
35 		addr.s_addr <<= 8;
36 		addr.s_addr |= (val & 0xFF);
37 		if (s) {
38 			s = (*e) ? e+1 : e;
39 		}
40 	}
41 
42 	addr.s_addr = htonl(addr.s_addr);
43 	return addr;
44 }
45 
string_to_enetaddr(const char * addr,uint8_t * enetaddr)46 void string_to_enetaddr(const char *addr, uint8_t *enetaddr)
47 {
48 	char *end;
49 	int i;
50 
51 	if (!enetaddr)
52 		return;
53 
54 	for (i = 0; i < 6; ++i) {
55 		enetaddr[i] = addr ? simple_strtoul(addr, &end, 16) : 0;
56 		if (addr)
57 			addr = (*end) ? end + 1 : end;
58 	}
59 }
60 
compute_ip_checksum(const void * vptr,uint nbytes)61 uint compute_ip_checksum(const void *vptr, uint nbytes)
62 {
63 	int sum, oddbyte;
64 	const unsigned short *ptr = vptr;
65 
66 	sum = 0;
67 	while (nbytes > 1) {
68 		sum += *ptr++;
69 		nbytes -= 2;
70 	}
71 	if (nbytes == 1) {
72 		oddbyte = 0;
73 		((u8 *)&oddbyte)[0] = *(u8 *)ptr;
74 		((u8 *)&oddbyte)[1] = 0;
75 		sum += oddbyte;
76 	}
77 	sum = (sum >> 16) + (sum & 0xffff);
78 	sum += (sum >> 16);
79 	sum = ~sum & 0xffff;
80 
81 	return sum;
82 }
83 
add_ip_checksums(uint offset,uint sum,uint new)84 uint add_ip_checksums(uint offset, uint sum, uint new)
85 {
86 	ulong checksum;
87 
88 	sum = ~sum & 0xffff;
89 	new = ~new & 0xffff;
90 	if (offset & 1) {
91 		/*
92 		 * byte-swap the sum if it came from an odd offset; since the
93 		 * computation is endian-independent this works.
94 		 */
95 		new = ((new >> 8) & 0xff) | ((new << 8) & 0xff00);
96 	}
97 	checksum = sum + new;
98 	if (checksum > 0xffff)
99 		checksum -= 0xffff;
100 
101 	return (~checksum) & 0xffff;
102 }
103 
ip_checksum_ok(const void * addr,uint nbytes)104 int ip_checksum_ok(const void *addr, uint nbytes)
105 {
106 	return !(compute_ip_checksum(addr, nbytes) & 0xfffe);
107 }
108