]> Git Repo - J-u-boot.git/blob - lib/net_utils.c
Merge tag 'v2025.01-rc3' into next
[J-u-boot.git] / lib / net_utils.c
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, [email protected]
9  * Copyright 2009 Dirk Behme, [email protected]
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 {
18         struct in_addr addr;
19         char *e;
20         int i;
21
22         addr.s_addr = 0;
23         if (s == NULL)
24                 return addr;
25
26         for (addr.s_addr = 0, i = 0; i < 4; ++i) {
27                 ulong val = s ? dectoul(s, &e) : 0;
28                 if (val > 255) {
29                         addr.s_addr = 0;
30                         return addr;
31                 }
32                 if (i != 3 && *e != '.') {
33                         addr.s_addr = 0;
34                         return addr;
35                 }
36                 addr.s_addr <<= 8;
37                 addr.s_addr |= (val & 0xFF);
38                 if (s) {
39                         s = (*e) ? e+1 : e;
40                 }
41         }
42
43         addr.s_addr = htonl(addr.s_addr);
44         return addr;
45 }
46
47 #if IS_ENABLED(CONFIG_IPV6)
48 int 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
150 out_err:
151         return -1;
152 }
153 #endif
154
155 void 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
166 void 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) {
175                 enetaddr[i] = addr ? hextoul(addr, &end) : 0;
176                 if (addr)
177                         addr = (*end) ? end + 1 : end;
178         }
179 }
180
181 uint 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
204 uint 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
224 int ip_checksum_ok(const void *addr, uint nbytes)
225 {
226         return !(compute_ip_checksum(addr, nbytes) & 0xfffe);
227 }
This page took 0.037609 seconds and 4 git commands to generate.