0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013 #include <linux/module.h>
0014 #include <linux/jiffies.h>
0015 #include <linux/kernel.h>
0016 #include <linux/ctype.h>
0017 #include <linux/inet.h>
0018 #include <linux/mm.h>
0019 #include <linux/net.h>
0020 #include <linux/string.h>
0021 #include <linux/types.h>
0022 #include <linux/percpu.h>
0023 #include <linux/init.h>
0024 #include <linux/ratelimit.h>
0025 #include <linux/socket.h>
0026
0027 #include <net/sock.h>
0028 #include <net/net_ratelimit.h>
0029 #include <net/ipv6.h>
0030
0031 #include <asm/byteorder.h>
0032 #include <linux/uaccess.h>
0033
0034 DEFINE_RATELIMIT_STATE(net_ratelimit_state, 5 * HZ, 10);
0035
0036
0037
0038 int net_ratelimit(void)
0039 {
0040 return __ratelimit(&net_ratelimit_state);
0041 }
0042 EXPORT_SYMBOL(net_ratelimit);
0043
0044
0045
0046
0047
0048
0049
0050 __be32 in_aton(const char *str)
0051 {
0052 unsigned int l;
0053 unsigned int val;
0054 int i;
0055
0056 l = 0;
0057 for (i = 0; i < 4; i++) {
0058 l <<= 8;
0059 if (*str != '\0') {
0060 val = 0;
0061 while (*str != '\0' && *str != '.' && *str != '\n') {
0062 val *= 10;
0063 val += *str - '0';
0064 str++;
0065 }
0066 l |= val;
0067 if (*str != '\0')
0068 str++;
0069 }
0070 }
0071 return htonl(l);
0072 }
0073 EXPORT_SYMBOL(in_aton);
0074
0075 #define IN6PTON_XDIGIT 0x00010000
0076 #define IN6PTON_DIGIT 0x00020000
0077 #define IN6PTON_COLON_MASK 0x00700000
0078 #define IN6PTON_COLON_1 0x00100000
0079 #define IN6PTON_COLON_2 0x00200000
0080 #define IN6PTON_COLON_1_2 0x00400000
0081 #define IN6PTON_DOT 0x00800000
0082 #define IN6PTON_DELIM 0x10000000
0083 #define IN6PTON_NULL 0x20000000
0084 #define IN6PTON_UNKNOWN 0x40000000
0085
0086 static inline int xdigit2bin(char c, int delim)
0087 {
0088 int val;
0089
0090 if (c == delim || c == '\0')
0091 return IN6PTON_DELIM;
0092 if (c == ':')
0093 return IN6PTON_COLON_MASK;
0094 if (c == '.')
0095 return IN6PTON_DOT;
0096
0097 val = hex_to_bin(c);
0098 if (val >= 0)
0099 return val | IN6PTON_XDIGIT | (val < 10 ? IN6PTON_DIGIT : 0);
0100
0101 if (delim == -1)
0102 return IN6PTON_DELIM;
0103 return IN6PTON_UNKNOWN;
0104 }
0105
0106
0107
0108
0109
0110
0111
0112
0113
0114
0115
0116
0117
0118 int in4_pton(const char *src, int srclen,
0119 u8 *dst,
0120 int delim, const char **end)
0121 {
0122 const char *s;
0123 u8 *d;
0124 u8 dbuf[4];
0125 int ret = 0;
0126 int i;
0127 int w = 0;
0128
0129 if (srclen < 0)
0130 srclen = strlen(src);
0131 s = src;
0132 d = dbuf;
0133 i = 0;
0134 while (1) {
0135 int c;
0136 c = xdigit2bin(srclen > 0 ? *s : '\0', delim);
0137 if (!(c & (IN6PTON_DIGIT | IN6PTON_DOT | IN6PTON_DELIM | IN6PTON_COLON_MASK))) {
0138 goto out;
0139 }
0140 if (c & (IN6PTON_DOT | IN6PTON_DELIM | IN6PTON_COLON_MASK)) {
0141 if (w == 0)
0142 goto out;
0143 *d++ = w & 0xff;
0144 w = 0;
0145 i++;
0146 if (c & (IN6PTON_DELIM | IN6PTON_COLON_MASK)) {
0147 if (i != 4)
0148 goto out;
0149 break;
0150 }
0151 goto cont;
0152 }
0153 w = (w * 10) + c;
0154 if ((w & 0xffff) > 255) {
0155 goto out;
0156 }
0157 cont:
0158 if (i >= 4)
0159 goto out;
0160 s++;
0161 srclen--;
0162 }
0163 ret = 1;
0164 memcpy(dst, dbuf, sizeof(dbuf));
0165 out:
0166 if (end)
0167 *end = s;
0168 return ret;
0169 }
0170 EXPORT_SYMBOL(in4_pton);
0171
0172
0173
0174
0175
0176
0177
0178
0179
0180
0181
0182
0183
0184 int in6_pton(const char *src, int srclen,
0185 u8 *dst,
0186 int delim, const char **end)
0187 {
0188 const char *s, *tok = NULL;
0189 u8 *d, *dc = NULL;
0190 u8 dbuf[16];
0191 int ret = 0;
0192 int i;
0193 int state = IN6PTON_COLON_1_2 | IN6PTON_XDIGIT | IN6PTON_NULL;
0194 int w = 0;
0195
0196 memset(dbuf, 0, sizeof(dbuf));
0197
0198 s = src;
0199 d = dbuf;
0200 if (srclen < 0)
0201 srclen = strlen(src);
0202
0203 while (1) {
0204 int c;
0205
0206 c = xdigit2bin(srclen > 0 ? *s : '\0', delim);
0207 if (!(c & state))
0208 goto out;
0209 if (c & (IN6PTON_DELIM | IN6PTON_COLON_MASK)) {
0210
0211 if (!(state & IN6PTON_NULL)) {
0212 *d++ = (w >> 8) & 0xff;
0213 *d++ = w & 0xff;
0214 }
0215 w = 0;
0216 if (c & IN6PTON_DELIM) {
0217
0218 break;
0219 }
0220
0221
0222
0223
0224
0225 switch (state & IN6PTON_COLON_MASK) {
0226 case IN6PTON_COLON_2:
0227 dc = d;
0228 state = IN6PTON_XDIGIT | IN6PTON_DELIM;
0229 if (dc - dbuf >= sizeof(dbuf))
0230 state |= IN6PTON_NULL;
0231 break;
0232 case IN6PTON_COLON_1|IN6PTON_COLON_1_2:
0233 state = IN6PTON_XDIGIT | IN6PTON_COLON_2;
0234 break;
0235 case IN6PTON_COLON_1:
0236 state = IN6PTON_XDIGIT;
0237 break;
0238 case IN6PTON_COLON_1_2:
0239 state = IN6PTON_COLON_2;
0240 break;
0241 default:
0242 state = 0;
0243 }
0244 tok = s + 1;
0245 goto cont;
0246 }
0247
0248 if (c & IN6PTON_DOT) {
0249 ret = in4_pton(tok ? tok : s, srclen + (int)(s - tok), d, delim, &s);
0250 if (ret > 0) {
0251 d += 4;
0252 break;
0253 }
0254 goto out;
0255 }
0256
0257 w = (w << 4) | (0xff & c);
0258 state = IN6PTON_COLON_1 | IN6PTON_DELIM;
0259 if (!(w & 0xf000)) {
0260 state |= IN6PTON_XDIGIT;
0261 }
0262 if (!dc && d + 2 < dbuf + sizeof(dbuf)) {
0263 state |= IN6PTON_COLON_1_2;
0264 state &= ~IN6PTON_DELIM;
0265 }
0266 if (d + 2 >= dbuf + sizeof(dbuf)) {
0267 state &= ~(IN6PTON_COLON_1|IN6PTON_COLON_1_2);
0268 }
0269 cont:
0270 if ((dc && d + 4 < dbuf + sizeof(dbuf)) ||
0271 d + 4 == dbuf + sizeof(dbuf)) {
0272 state |= IN6PTON_DOT;
0273 }
0274 if (d >= dbuf + sizeof(dbuf)) {
0275 state &= ~(IN6PTON_XDIGIT|IN6PTON_COLON_MASK);
0276 }
0277 s++;
0278 srclen--;
0279 }
0280
0281 i = 15; d--;
0282
0283 if (dc) {
0284 while (d >= dc)
0285 dst[i--] = *d--;
0286 while (i >= dc - dbuf)
0287 dst[i--] = 0;
0288 while (i >= 0)
0289 dst[i--] = *d--;
0290 } else
0291 memcpy(dst, dbuf, sizeof(dbuf));
0292
0293 ret = 1;
0294 out:
0295 if (end)
0296 *end = s;
0297 return ret;
0298 }
0299 EXPORT_SYMBOL(in6_pton);
0300
0301 static int inet4_pton(const char *src, u16 port_num,
0302 struct sockaddr_storage *addr)
0303 {
0304 struct sockaddr_in *addr4 = (struct sockaddr_in *)addr;
0305 int srclen = strlen(src);
0306
0307 if (srclen > INET_ADDRSTRLEN)
0308 return -EINVAL;
0309
0310 if (in4_pton(src, srclen, (u8 *)&addr4->sin_addr.s_addr,
0311 '\n', NULL) == 0)
0312 return -EINVAL;
0313
0314 addr4->sin_family = AF_INET;
0315 addr4->sin_port = htons(port_num);
0316
0317 return 0;
0318 }
0319
0320 static int inet6_pton(struct net *net, const char *src, u16 port_num,
0321 struct sockaddr_storage *addr)
0322 {
0323 struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)addr;
0324 const char *scope_delim;
0325 int srclen = strlen(src);
0326
0327 if (srclen > INET6_ADDRSTRLEN)
0328 return -EINVAL;
0329
0330 if (in6_pton(src, srclen, (u8 *)&addr6->sin6_addr.s6_addr,
0331 '%', &scope_delim) == 0)
0332 return -EINVAL;
0333
0334 if (ipv6_addr_type(&addr6->sin6_addr) & IPV6_ADDR_LINKLOCAL &&
0335 src + srclen != scope_delim && *scope_delim == '%') {
0336 struct net_device *dev;
0337 char scope_id[16];
0338 size_t scope_len = min_t(size_t, sizeof(scope_id) - 1,
0339 src + srclen - scope_delim - 1);
0340
0341 memcpy(scope_id, scope_delim + 1, scope_len);
0342 scope_id[scope_len] = '\0';
0343
0344 dev = dev_get_by_name(net, scope_id);
0345 if (dev) {
0346 addr6->sin6_scope_id = dev->ifindex;
0347 dev_put(dev);
0348 } else if (kstrtouint(scope_id, 0, &addr6->sin6_scope_id)) {
0349 return -EINVAL;
0350 }
0351 }
0352
0353 addr6->sin6_family = AF_INET6;
0354 addr6->sin6_port = htons(port_num);
0355
0356 return 0;
0357 }
0358
0359
0360
0361
0362
0363
0364
0365
0366
0367
0368
0369 int inet_pton_with_scope(struct net *net, __kernel_sa_family_t af,
0370 const char *src, const char *port, struct sockaddr_storage *addr)
0371 {
0372 u16 port_num;
0373 int ret = -EINVAL;
0374
0375 if (port) {
0376 if (kstrtou16(port, 0, &port_num))
0377 return -EINVAL;
0378 } else {
0379 port_num = 0;
0380 }
0381
0382 switch (af) {
0383 case AF_INET:
0384 ret = inet4_pton(src, port_num, addr);
0385 break;
0386 case AF_INET6:
0387 ret = inet6_pton(net, src, port_num, addr);
0388 break;
0389 case AF_UNSPEC:
0390 ret = inet4_pton(src, port_num, addr);
0391 if (ret)
0392 ret = inet6_pton(net, src, port_num, addr);
0393 break;
0394 default:
0395 pr_err("unexpected address family %d\n", af);
0396 }
0397
0398 return ret;
0399 }
0400 EXPORT_SYMBOL(inet_pton_with_scope);
0401
0402 bool inet_addr_is_any(struct sockaddr *addr)
0403 {
0404 if (addr->sa_family == AF_INET6) {
0405 struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)addr;
0406 const struct sockaddr_in6 in6_any =
0407 { .sin6_addr = IN6ADDR_ANY_INIT };
0408
0409 if (!memcmp(in6->sin6_addr.s6_addr,
0410 in6_any.sin6_addr.s6_addr, 16))
0411 return true;
0412 } else if (addr->sa_family == AF_INET) {
0413 struct sockaddr_in *in = (struct sockaddr_in *)addr;
0414
0415 if (in->sin_addr.s_addr == htonl(INADDR_ANY))
0416 return true;
0417 } else {
0418 pr_warn("unexpected address family %u\n", addr->sa_family);
0419 }
0420
0421 return false;
0422 }
0423 EXPORT_SYMBOL(inet_addr_is_any);
0424
0425 void inet_proto_csum_replace4(__sum16 *sum, struct sk_buff *skb,
0426 __be32 from, __be32 to, bool pseudohdr)
0427 {
0428 if (skb->ip_summed != CHECKSUM_PARTIAL) {
0429 csum_replace4(sum, from, to);
0430 if (skb->ip_summed == CHECKSUM_COMPLETE && pseudohdr)
0431 skb->csum = ~csum_add(csum_sub(~(skb->csum),
0432 (__force __wsum)from),
0433 (__force __wsum)to);
0434 } else if (pseudohdr)
0435 *sum = ~csum_fold(csum_add(csum_sub(csum_unfold(*sum),
0436 (__force __wsum)from),
0437 (__force __wsum)to));
0438 }
0439 EXPORT_SYMBOL(inet_proto_csum_replace4);
0440
0441
0442
0443
0444
0445
0446
0447
0448
0449
0450
0451
0452
0453
0454
0455
0456
0457
0458 void inet_proto_csum_replace16(__sum16 *sum, struct sk_buff *skb,
0459 const __be32 *from, const __be32 *to,
0460 bool pseudohdr)
0461 {
0462 __be32 diff[] = {
0463 ~from[0], ~from[1], ~from[2], ~from[3],
0464 to[0], to[1], to[2], to[3],
0465 };
0466 if (skb->ip_summed != CHECKSUM_PARTIAL) {
0467 *sum = csum_fold(csum_partial(diff, sizeof(diff),
0468 ~csum_unfold(*sum)));
0469 } else if (pseudohdr)
0470 *sum = ~csum_fold(csum_partial(diff, sizeof(diff),
0471 csum_unfold(*sum)));
0472 }
0473 EXPORT_SYMBOL(inet_proto_csum_replace16);
0474
0475 void inet_proto_csum_replace_by_diff(__sum16 *sum, struct sk_buff *skb,
0476 __wsum diff, bool pseudohdr)
0477 {
0478 if (skb->ip_summed != CHECKSUM_PARTIAL) {
0479 csum_replace_by_diff(sum, diff);
0480 if (skb->ip_summed == CHECKSUM_COMPLETE && pseudohdr)
0481 skb->csum = ~csum_sub(diff, skb->csum);
0482 } else if (pseudohdr) {
0483 *sum = ~csum_fold(csum_add(diff, csum_unfold(*sum)));
0484 }
0485 }
0486 EXPORT_SYMBOL(inet_proto_csum_replace_by_diff);