Tom Rini | 10e4779 | 2018-05-06 17:58:06 -0400 | [diff] [blame] | 1 | // SPDX-License-Identifier: GPL-2.0+ |
Dirk Behme | 8b3cc06 | 2010-01-03 08:33:58 +0100 | [diff] [blame] | 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 |
Dirk Behme | 8b3cc06 | 2010-01-03 08:33:58 +0100 | [diff] [blame] | 10 | */ |
| 11 | |
Simon Glass | 274e0b0 | 2020-05-10 11:39:56 -0600 | [diff] [blame] | 12 | #include <net.h> |
Viacheslav Mitrofanov | fb7968c | 2022-12-02 12:18:02 +0300 | [diff] [blame] | 13 | #include <net6.h> |
Tom Rini | a877ce1 | 2023-12-14 13:16:58 -0500 | [diff] [blame] | 14 | #include <vsprintf.h> |
Dirk Behme | 8b3cc06 | 2010-01-03 08:33:58 +0100 | [diff] [blame] | 15 | |
Joe Hershberger | 5874dec | 2015-04-08 01:41:01 -0500 | [diff] [blame] | 16 | struct in_addr string_to_ip(const char *s) |
Dirk Behme | 8b3cc06 | 2010-01-03 08:33:58 +0100 | [diff] [blame] | 17 | { |
Joe Hershberger | 5874dec | 2015-04-08 01:41:01 -0500 | [diff] [blame] | 18 | struct in_addr addr; |
Dirk Behme | 8b3cc06 | 2010-01-03 08:33:58 +0100 | [diff] [blame] | 19 | char *e; |
| 20 | int i; |
| 21 | |
Joe Hershberger | 5874dec | 2015-04-08 01:41:01 -0500 | [diff] [blame] | 22 | addr.s_addr = 0; |
Dirk Behme | 8b3cc06 | 2010-01-03 08:33:58 +0100 | [diff] [blame] | 23 | if (s == NULL) |
Joe Hershberger | 5874dec | 2015-04-08 01:41:01 -0500 | [diff] [blame] | 24 | return addr; |
Dirk Behme | 8b3cc06 | 2010-01-03 08:33:58 +0100 | [diff] [blame] | 25 | |
Joe Hershberger | 5874dec | 2015-04-08 01:41:01 -0500 | [diff] [blame] | 26 | for (addr.s_addr = 0, i = 0; i < 4; ++i) { |
Simon Glass | ff9b903 | 2021-07-24 09:03:30 -0600 | [diff] [blame] | 27 | ulong val = s ? dectoul(s, &e) : 0; |
Chris Packham | e917c36 | 2017-01-04 13:36:25 +1300 | [diff] [blame] | 28 | if (val > 255) { |
| 29 | addr.s_addr = 0; |
| 30 | return addr; |
| 31 | } |
Chris Packham | 0656248 | 2017-01-04 13:36:26 +1300 | [diff] [blame] | 32 | if (i != 3 && *e != '.') { |
| 33 | addr.s_addr = 0; |
| 34 | return addr; |
| 35 | } |
Joe Hershberger | 5874dec | 2015-04-08 01:41:01 -0500 | [diff] [blame] | 36 | addr.s_addr <<= 8; |
| 37 | addr.s_addr |= (val & 0xFF); |
Dirk Behme | 8b3cc06 | 2010-01-03 08:33:58 +0100 | [diff] [blame] | 38 | if (s) { |
| 39 | s = (*e) ? e+1 : e; |
| 40 | } |
| 41 | } |
| 42 | |
Joe Hershberger | 5874dec | 2015-04-08 01:41:01 -0500 | [diff] [blame] | 43 | addr.s_addr = htonl(addr.s_addr); |
| 44 | return addr; |
Dirk Behme | 8b3cc06 | 2010-01-03 08:33:58 +0100 | [diff] [blame] | 45 | } |
Joe Hershberger | 8e7545e | 2019-09-13 19:21:16 -0500 | [diff] [blame] | 46 | |
Viacheslav Mitrofanov | fb7968c | 2022-12-02 12:18:02 +0300 | [diff] [blame] | 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 | |
Joe Hershberger | 8e7545e | 2019-09-13 19:21:16 -0500 | [diff] [blame] | 155 | void string_to_enetaddr(const char *addr, uint8_t *enetaddr) |
| 156 | { |
| 157 | char *end; |
| 158 | int i; |
| 159 | |
| 160 | if (!enetaddr) |
| 161 | return; |
| 162 | |
| 163 | for (i = 0; i < 6; ++i) { |
Simon Glass | 3ff49ec | 2021-07-24 09:03:29 -0600 | [diff] [blame] | 164 | enetaddr[i] = addr ? hextoul(addr, &end) : 0; |
Joe Hershberger | 8e7545e | 2019-09-13 19:21:16 -0500 | [diff] [blame] | 165 | if (addr) |
| 166 | addr = (*end) ? end + 1 : end; |
| 167 | } |
| 168 | } |
Simon Glass | d70d8d8 | 2019-12-06 21:41:39 -0700 | [diff] [blame] | 169 | |
| 170 | uint compute_ip_checksum(const void *vptr, uint nbytes) |
| 171 | { |
| 172 | int sum, oddbyte; |
| 173 | const unsigned short *ptr = vptr; |
| 174 | |
| 175 | sum = 0; |
| 176 | while (nbytes > 1) { |
| 177 | sum += *ptr++; |
| 178 | nbytes -= 2; |
| 179 | } |
| 180 | if (nbytes == 1) { |
| 181 | oddbyte = 0; |
| 182 | ((u8 *)&oddbyte)[0] = *(u8 *)ptr; |
| 183 | ((u8 *)&oddbyte)[1] = 0; |
| 184 | sum += oddbyte; |
| 185 | } |
| 186 | sum = (sum >> 16) + (sum & 0xffff); |
| 187 | sum += (sum >> 16); |
| 188 | sum = ~sum & 0xffff; |
| 189 | |
| 190 | return sum; |
| 191 | } |
| 192 | |
| 193 | uint add_ip_checksums(uint offset, uint sum, uint new) |
| 194 | { |
| 195 | ulong checksum; |
| 196 | |
| 197 | sum = ~sum & 0xffff; |
| 198 | new = ~new & 0xffff; |
| 199 | if (offset & 1) { |
| 200 | /* |
| 201 | * byte-swap the sum if it came from an odd offset; since the |
| 202 | * computation is endian-independent this works. |
| 203 | */ |
| 204 | new = ((new >> 8) & 0xff) | ((new << 8) & 0xff00); |
| 205 | } |
| 206 | checksum = sum + new; |
| 207 | if (checksum > 0xffff) |
| 208 | checksum -= 0xffff; |
| 209 | |
| 210 | return (~checksum) & 0xffff; |
| 211 | } |
| 212 | |
| 213 | int ip_checksum_ok(const void *addr, uint nbytes) |
| 214 | { |
| 215 | return !(compute_ip_checksum(addr, nbytes) & 0xfffe); |
| 216 | } |