net_utils.c 4.0 KB

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