]>
Commit | Line | Data |
---|---|---|
83d290c5 | 1 | // SPDX-License-Identifier: GPL-2.0+ |
6a45e384 DB |
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] | |
6a45e384 DB |
10 | */ |
11 | ||
90526e9f | 12 | #include <net.h> |
2f7f2f2a | 13 | #include <net6.h> |
467382ca | 14 | #include <vsprintf.h> |
6a45e384 | 15 | |
049a95a7 | 16 | struct in_addr string_to_ip(const char *s) |
6a45e384 | 17 | { |
049a95a7 | 18 | struct in_addr addr; |
6a45e384 DB |
19 | char *e; |
20 | int i; | |
21 | ||
049a95a7 | 22 | addr.s_addr = 0; |
6a45e384 | 23 | if (s == NULL) |
049a95a7 | 24 | return addr; |
6a45e384 | 25 | |
049a95a7 | 26 | for (addr.s_addr = 0, i = 0; i < 4; ++i) { |
0b1284eb | 27 | ulong val = s ? dectoul(s, &e) : 0; |
d921ed9a CP |
28 | if (val > 255) { |
29 | addr.s_addr = 0; | |
30 | return addr; | |
31 | } | |
f267e40f CP |
32 | if (i != 3 && *e != '.') { |
33 | addr.s_addr = 0; | |
34 | return addr; | |
35 | } | |
049a95a7 JH |
36 | addr.s_addr <<= 8; |
37 | addr.s_addr |= (val & 0xFF); | |
6a45e384 DB |
38 | if (s) { |
39 | s = (*e) ? e+1 : e; | |
40 | } | |
41 | } | |
42 | ||
049a95a7 JH |
43 | addr.s_addr = htonl(addr.s_addr); |
44 | return addr; | |
6a45e384 | 45 | } |
fb8977c5 | 46 | |
2f7f2f2a VM |
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 | ||
9063dba2 AC |
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 | ||
fb8977c5 JH |
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) { | |
7e5f460e | 175 | enetaddr[i] = addr ? hextoul(addr, &end) : 0; |
fb8977c5 JH |
176 | if (addr) |
177 | addr = (*end) ? end + 1 : end; | |
178 | } | |
179 | } | |
d721001f SG |
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 | } |