blob: 621f6512b62b7d6f8b741839e67e4cf51e010003 [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Dirk Behme6a45e382010-01-03 08:33:58 +01002/*
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
Dirk Behme6a45e382010-01-03 08:33:58 +010010 */
11
Simon Glass90526e92020-05-10 11:39:56 -060012#include <net.h>
Viacheslav Mitrofanov2f7f2f22022-12-02 12:18:02 +030013#include <net6.h>
Tom Rini467382c2023-12-14 13:16:58 -050014#include <vsprintf.h>
Dirk Behme6a45e382010-01-03 08:33:58 +010015
Joe Hershberger049a95a2015-04-08 01:41:01 -050016struct in_addr string_to_ip(const char *s)
Dirk Behme6a45e382010-01-03 08:33:58 +010017{
Joe Hershberger049a95a2015-04-08 01:41:01 -050018 struct in_addr addr;
Dirk Behme6a45e382010-01-03 08:33:58 +010019 char *e;
20 int i;
21
Joe Hershberger049a95a2015-04-08 01:41:01 -050022 addr.s_addr = 0;
Dirk Behme6a45e382010-01-03 08:33:58 +010023 if (s == NULL)
Joe Hershberger049a95a2015-04-08 01:41:01 -050024 return addr;
Dirk Behme6a45e382010-01-03 08:33:58 +010025
Joe Hershberger049a95a2015-04-08 01:41:01 -050026 for (addr.s_addr = 0, i = 0; i < 4; ++i) {
Simon Glass0b1284e2021-07-24 09:03:30 -060027 ulong val = s ? dectoul(s, &e) : 0;
Chris Packhamd921ed92017-01-04 13:36:25 +130028 if (val > 255) {
29 addr.s_addr = 0;
30 return addr;
31 }
Chris Packhamf267e402017-01-04 13:36:26 +130032 if (i != 3 && *e != '.') {
33 addr.s_addr = 0;
34 return addr;
35 }
Joe Hershberger049a95a2015-04-08 01:41:01 -050036 addr.s_addr <<= 8;
37 addr.s_addr |= (val & 0xFF);
Dirk Behme6a45e382010-01-03 08:33:58 +010038 if (s) {
39 s = (*e) ? e+1 : e;
40 }
41 }
42
Joe Hershberger049a95a2015-04-08 01:41:01 -050043 addr.s_addr = htonl(addr.s_addr);
44 return addr;
Dirk Behme6a45e382010-01-03 08:33:58 +010045}
Joe Hershbergerfb8977c2019-09-13 19:21:16 -050046
Viacheslav Mitrofanov2f7f2f22022-12-02 12:18:02 +030047#if IS_ENABLED(CONFIG_IPV6)
48int string_to_ip6(const char *str, size_t len, struct in6_addr *addr)
49{
50 int colon_count = 0;
51 int found_double_colon = 0;
52 int xstart = 0; /* first zero (double colon) */
53 int section_num = 7; /* num words the double colon represents */
54 int i;
55 const char *s = str;
56 const char *const e = s + len;
57 struct in_addr zero_ip = {.s_addr = 0};
58
59 if (!str)
60 return -1;
61
62 /* First pass, verify the syntax and locate the double colon */
63 while (s < e) {
64 while (s < e && isxdigit((int)*s))
65 s++;
66 if (*s == '\0')
67 break;
68 if (*s != ':') {
69 if (*s == '.' && section_num >= 2) {
70 struct in_addr v4;
71
72 while (s != str && *(s - 1) != ':')
73 --s;
74 v4 = string_to_ip(s);
75 if (memcmp(&zero_ip, &v4,
76 sizeof(struct in_addr)) != 0) {
77 section_num -= 2;
78 break;
79 }
80 }
81 /* This could be a valid address */
82 break;
83 }
84 if (s == str) {
85 /* The address begins with a colon */
86 if (*++s != ':')
87 /* Must start with a double colon or a number */
88 goto out_err;
89 } else {
90 s++;
91 if (found_double_colon)
92 section_num--;
93 else
94 xstart++;
95 }
96
97 if (*s == ':') {
98 if (found_double_colon)
99 /* Two double colons are not allowed */
100 goto out_err;
101 found_double_colon = 1;
102 section_num -= xstart;
103 s++;
104 }
105
106 if (++colon_count == 7)
107 /* Found all colons */
108 break;
109 ++s;
110 }
111
112 if (colon_count == 0)
113 goto out_err;
114 if (*--s == ':')
115 section_num++;
116
117 /* Second pass, read the address */
118 s = str;
119 for (i = 0; i < 8; i++) {
120 int val = 0;
121 char *end;
122
123 if (found_double_colon &&
124 i >= xstart && i < xstart + section_num) {
125 addr->s6_addr16[i] = 0;
126 continue;
127 }
128 while (*s == ':')
129 s++;
130
131 if (i == 6 && isdigit((int)*s)) {
132 struct in_addr v4 = string_to_ip(s);
133
134 if (memcmp(&zero_ip, &v4,
135 sizeof(struct in_addr)) != 0) {
136 /* Ending with :IPv4-address */
137 addr->s6_addr32[3] = v4.s_addr;
138 break;
139 }
140 }
141
142 val = simple_strtoul(s, &end, 16);
143 if (end != e && *end != '\0' && *end != ':')
144 goto out_err;
145 addr->s6_addr16[i] = htons(val);
146 s = end;
147 }
148 return 0;
149
150out_err:
151 return -1;
152}
153#endif
154
Adriano Cordova9063dba2024-11-11 18:09:45 -0300155void ip_to_string(struct in_addr x, char *s)
156{
157 x.s_addr = ntohl(x.s_addr);
158 sprintf(s, "%d.%d.%d.%d",
159 (int) ((x.s_addr >> 24) & 0xff),
160 (int) ((x.s_addr >> 16) & 0xff),
161 (int) ((x.s_addr >> 8) & 0xff),
162 (int) ((x.s_addr >> 0) & 0xff)
163 );
164}
165
Joe Hershbergerfb8977c2019-09-13 19:21:16 -0500166void string_to_enetaddr(const char *addr, uint8_t *enetaddr)
167{
168 char *end;
169 int i;
170
171 if (!enetaddr)
172 return;
173
174 for (i = 0; i < 6; ++i) {
Simon Glass7e5f4602021-07-24 09:03:29 -0600175 enetaddr[i] = addr ? hextoul(addr, &end) : 0;
Joe Hershbergerfb8977c2019-09-13 19:21:16 -0500176 if (addr)
177 addr = (*end) ? end + 1 : end;
178 }
179}
Simon Glassd7210012019-12-06 21:41:39 -0700180
181uint compute_ip_checksum(const void *vptr, uint nbytes)
182{
183 int sum, oddbyte;
184 const unsigned short *ptr = vptr;
185
186 sum = 0;
187 while (nbytes > 1) {
188 sum += *ptr++;
189 nbytes -= 2;
190 }
191 if (nbytes == 1) {
192 oddbyte = 0;
193 ((u8 *)&oddbyte)[0] = *(u8 *)ptr;
194 ((u8 *)&oddbyte)[1] = 0;
195 sum += oddbyte;
196 }
197 sum = (sum >> 16) + (sum & 0xffff);
198 sum += (sum >> 16);
199 sum = ~sum & 0xffff;
200
201 return sum;
202}
203
204uint add_ip_checksums(uint offset, uint sum, uint new)
205{
206 ulong checksum;
207
208 sum = ~sum & 0xffff;
209 new = ~new & 0xffff;
210 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 new = ((new >> 8) & 0xff) | ((new << 8) & 0xff00);
216 }
217 checksum = sum + new;
218 if (checksum > 0xffff)
219 checksum -= 0xffff;
220
221 return (~checksum) & 0xffff;
222}
223
224int ip_checksum_ok(const void *addr, uint nbytes)
225{
226 return !(compute_ip_checksum(addr, nbytes) & 0xfffe);
227}