/src/u-boot/lib/net_utils.c
Line | Count | Source |
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 <net.h> |
13 | | #include <net6.h> |
14 | | #include <vsprintf.h> |
15 | | |
16 | | struct in_addr string_to_ip(const char *s) |
17 | 0 | { |
18 | 0 | struct in_addr addr; |
19 | 0 | char *e; |
20 | 0 | int i; |
21 | |
|
22 | 0 | addr.s_addr = 0; |
23 | 0 | if (s == NULL) |
24 | 0 | return addr; |
25 | | |
26 | 0 | for (addr.s_addr = 0, i = 0; i < 4; ++i) { |
27 | 0 | ulong val = s ? dectoul(s, &e) : 0; |
28 | 0 | if (val > 255) { |
29 | 0 | addr.s_addr = 0; |
30 | 0 | return addr; |
31 | 0 | } |
32 | 0 | if (i != 3 && *e != '.') { |
33 | 0 | addr.s_addr = 0; |
34 | 0 | return addr; |
35 | 0 | } |
36 | 0 | addr.s_addr <<= 8; |
37 | 0 | addr.s_addr |= (val & 0xFF); |
38 | 0 | if (s) { |
39 | 0 | s = (*e) ? e+1 : e; |
40 | 0 | } |
41 | 0 | } |
42 | | |
43 | 0 | addr.s_addr = htonl(addr.s_addr); |
44 | 0 | return addr; |
45 | 0 | } |
46 | | |
47 | | #if IS_ENABLED(CONFIG_IPV6) |
48 | | int string_to_ip6(const char *str, size_t len, struct in6_addr *addr) |
49 | 0 | { |
50 | 0 | int colon_count = 0; |
51 | 0 | int found_double_colon = 0; |
52 | 0 | int xstart = 0; /* first zero (double colon) */ |
53 | 0 | int section_num = 7; /* num words the double colon represents */ |
54 | 0 | int i; |
55 | 0 | const char *s = str; |
56 | 0 | const char *const e = s + len; |
57 | 0 | struct in_addr zero_ip = {.s_addr = 0}; |
58 | |
|
59 | 0 | if (!str) |
60 | 0 | return -1; |
61 | | |
62 | | /* First pass, verify the syntax and locate the double colon */ |
63 | 0 | while (s < e) { |
64 | 0 | while (s < e && isxdigit((int)*s)) |
65 | 0 | s++; |
66 | 0 | if (*s == '\0') |
67 | 0 | break; |
68 | 0 | if (*s != ':') { |
69 | 0 | if (*s == '.' && section_num >= 2) { |
70 | 0 | struct in_addr v4; |
71 | |
|
72 | 0 | while (s != str && *(s - 1) != ':') |
73 | 0 | --s; |
74 | 0 | v4 = string_to_ip(s); |
75 | 0 | if (memcmp(&zero_ip, &v4, |
76 | 0 | sizeof(struct in_addr)) != 0) { |
77 | 0 | section_num -= 2; |
78 | 0 | break; |
79 | 0 | } |
80 | 0 | } |
81 | | /* This could be a valid address */ |
82 | 0 | break; |
83 | 0 | } |
84 | 0 | if (s == str) { |
85 | | /* The address begins with a colon */ |
86 | 0 | if (*++s != ':') |
87 | | /* Must start with a double colon or a number */ |
88 | 0 | goto out_err; |
89 | 0 | } else { |
90 | 0 | s++; |
91 | 0 | if (found_double_colon) |
92 | 0 | section_num--; |
93 | 0 | else |
94 | 0 | xstart++; |
95 | 0 | } |
96 | | |
97 | 0 | if (*s == ':') { |
98 | 0 | if (found_double_colon) |
99 | | /* Two double colons are not allowed */ |
100 | 0 | goto out_err; |
101 | 0 | found_double_colon = 1; |
102 | 0 | section_num -= xstart; |
103 | 0 | s++; |
104 | 0 | } |
105 | | |
106 | 0 | if (++colon_count == 7) |
107 | | /* Found all colons */ |
108 | 0 | break; |
109 | 0 | ++s; |
110 | 0 | } |
111 | | |
112 | 0 | if (colon_count == 0) |
113 | 0 | goto out_err; |
114 | 0 | if (*--s == ':') |
115 | 0 | section_num++; |
116 | | |
117 | | /* Second pass, read the address */ |
118 | 0 | s = str; |
119 | 0 | for (i = 0; i < 8; i++) { |
120 | 0 | int val = 0; |
121 | 0 | char *end; |
122 | |
|
123 | 0 | if (found_double_colon && |
124 | 0 | i >= xstart && i < xstart + section_num) { |
125 | 0 | addr->s6_addr16[i] = 0; |
126 | 0 | continue; |
127 | 0 | } |
128 | 0 | while (*s == ':') |
129 | 0 | s++; |
130 | |
|
131 | 0 | if (i == 6 && isdigit((int)*s)) { |
132 | 0 | struct in_addr v4 = string_to_ip(s); |
133 | |
|
134 | 0 | if (memcmp(&zero_ip, &v4, |
135 | 0 | sizeof(struct in_addr)) != 0) { |
136 | | /* Ending with :IPv4-address */ |
137 | 0 | addr->s6_addr32[3] = v4.s_addr; |
138 | 0 | break; |
139 | 0 | } |
140 | 0 | } |
141 | | |
142 | 0 | val = simple_strtoul(s, &end, 16); |
143 | 0 | if (end != e && *end != '\0' && *end != ':') |
144 | 0 | goto out_err; |
145 | 0 | addr->s6_addr16[i] = htons(val); |
146 | 0 | s = end; |
147 | 0 | } |
148 | 0 | return 0; |
149 | | |
150 | 0 | out_err: |
151 | 0 | return -1; |
152 | 0 | } |
153 | | #endif |
154 | | |
155 | | void ip_to_string(struct in_addr x, char *s) |
156 | 0 | { |
157 | 0 | x.s_addr = ntohl(x.s_addr); |
158 | 0 | sprintf(s, "%d.%d.%d.%d", |
159 | 0 | (int) ((x.s_addr >> 24) & 0xff), |
160 | 0 | (int) ((x.s_addr >> 16) & 0xff), |
161 | 0 | (int) ((x.s_addr >> 8) & 0xff), |
162 | 0 | (int) ((x.s_addr >> 0) & 0xff) |
163 | 0 | ); |
164 | 0 | } |
165 | | |
166 | | void string_to_enetaddr(const char *addr, uint8_t *enetaddr) |
167 | 0 | { |
168 | 0 | char *end; |
169 | 0 | int i; |
170 | |
|
171 | 0 | if (!enetaddr) |
172 | 0 | return; |
173 | | |
174 | 0 | for (i = 0; i < 6; ++i) { |
175 | 0 | enetaddr[i] = addr ? hextoul(addr, &end) : 0; |
176 | 0 | if (addr) |
177 | 0 | addr = (*end) ? end + 1 : end; |
178 | 0 | } |
179 | 0 | } |
180 | | |
181 | | uint compute_ip_checksum(const void *vptr, uint nbytes) |
182 | 0 | { |
183 | 0 | int sum, oddbyte; |
184 | 0 | const unsigned short *ptr = vptr; |
185 | |
|
186 | 0 | sum = 0; |
187 | 0 | while (nbytes > 1) { |
188 | 0 | sum += *ptr++; |
189 | 0 | nbytes -= 2; |
190 | 0 | } |
191 | 0 | if (nbytes == 1) { |
192 | 0 | oddbyte = 0; |
193 | 0 | ((u8 *)&oddbyte)[0] = *(u8 *)ptr; |
194 | 0 | ((u8 *)&oddbyte)[1] = 0; |
195 | 0 | sum += oddbyte; |
196 | 0 | } |
197 | 0 | sum = (sum >> 16) + (sum & 0xffff); |
198 | 0 | sum += (sum >> 16); |
199 | 0 | sum = ~sum & 0xffff; |
200 | |
|
201 | 0 | return sum; |
202 | 0 | } |
203 | | |
204 | | uint add_ip_checksums(uint offset, uint sum, uint new) |
205 | 0 | { |
206 | 0 | ulong checksum; |
207 | |
|
208 | 0 | sum = ~sum & 0xffff; |
209 | 0 | new = ~new & 0xffff; |
210 | 0 | if (offset & 1) { |
211 | | /* |
212 | | * byte-swap the sum if it came from an odd offset; since the |
213 | | * computation is endian-independent this works. |
214 | | */ |
215 | 0 | new = ((new >> 8) & 0xff) | ((new << 8) & 0xff00); |
216 | 0 | } |
217 | 0 | checksum = sum + new; |
218 | 0 | if (checksum > 0xffff) |
219 | 0 | checksum -= 0xffff; |
220 | |
|
221 | 0 | return (~checksum) & 0xffff; |
222 | 0 | } |
223 | | |
224 | | int ip_checksum_ok(const void *addr, uint nbytes) |
225 | 0 | { |
226 | 0 | return !(compute_ip_checksum(addr, nbytes) & 0xfffe); |
227 | 0 | } |