linux/net/core/utils.c
<<
>>
Prefs
   1/*
   2 *      Generic address resultion entity
   3 *
   4 *      Authors:
   5 *      net_random Alan Cox
   6 *      net_ratelimit Andi Kleen
   7 *      in{4,6}_pton YOSHIFUJI Hideaki, Copyright (C)2006 USAGI/WIDE Project
   8 *
   9 *      Created by Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
  10 *
  11 *      This program is free software; you can redistribute it and/or
  12 *      modify it under the terms of the GNU General Public License
  13 *      as published by the Free Software Foundation; either version
  14 *      2 of the License, or (at your option) any later version.
  15 */
  16
  17#include <linux/module.h>
  18#include <linux/jiffies.h>
  19#include <linux/kernel.h>
  20#include <linux/ctype.h>
  21#include <linux/inet.h>
  22#include <linux/mm.h>
  23#include <linux/net.h>
  24#include <linux/string.h>
  25#include <linux/types.h>
  26#include <linux/percpu.h>
  27#include <linux/init.h>
  28#include <linux/ratelimit.h>
  29#include <linux/socket.h>
  30
  31#include <net/sock.h>
  32#include <net/net_ratelimit.h>
  33#include <net/ipv6.h>
  34
  35#include <asm/byteorder.h>
  36#include <linux/uaccess.h>
  37
  38DEFINE_RATELIMIT_STATE(net_ratelimit_state, 5 * HZ, 10);
  39/*
  40 * All net warning printk()s should be guarded by this function.
  41 */
  42int net_ratelimit(void)
  43{
  44        return __ratelimit(&net_ratelimit_state);
  45}
  46EXPORT_SYMBOL(net_ratelimit);
  47
  48/*
  49 * Convert an ASCII string to binary IP.
  50 * This is outside of net/ipv4/ because various code that uses IP addresses
  51 * is otherwise not dependent on the TCP/IP stack.
  52 */
  53
  54__be32 in_aton(const char *str)
  55{
  56        unsigned int l;
  57        unsigned int val;
  58        int i;
  59
  60        l = 0;
  61        for (i = 0; i < 4; i++) {
  62                l <<= 8;
  63                if (*str != '\0') {
  64                        val = 0;
  65                        while (*str != '\0' && *str != '.' && *str != '\n') {
  66                                val *= 10;
  67                                val += *str - '0';
  68                                str++;
  69                        }
  70                        l |= val;
  71                        if (*str != '\0')
  72                                str++;
  73                }
  74        }
  75        return htonl(l);
  76}
  77EXPORT_SYMBOL(in_aton);
  78
  79#define IN6PTON_XDIGIT          0x00010000
  80#define IN6PTON_DIGIT           0x00020000
  81#define IN6PTON_COLON_MASK      0x00700000
  82#define IN6PTON_COLON_1         0x00100000      /* single : requested */
  83#define IN6PTON_COLON_2         0x00200000      /* second : requested */
  84#define IN6PTON_COLON_1_2       0x00400000      /* :: requested */
  85#define IN6PTON_DOT             0x00800000      /* . */
  86#define IN6PTON_DELIM           0x10000000
  87#define IN6PTON_NULL            0x20000000      /* first/tail */
  88#define IN6PTON_UNKNOWN         0x40000000
  89
  90static inline int xdigit2bin(char c, int delim)
  91{
  92        int val;
  93
  94        if (c == delim || c == '\0')
  95                return IN6PTON_DELIM;
  96        if (c == ':')
  97                return IN6PTON_COLON_MASK;
  98        if (c == '.')
  99                return IN6PTON_DOT;
 100
 101        val = hex_to_bin(c);
 102        if (val >= 0)
 103                return val | IN6PTON_XDIGIT | (val < 10 ? IN6PTON_DIGIT : 0);
 104
 105        if (delim == -1)
 106                return IN6PTON_DELIM;
 107        return IN6PTON_UNKNOWN;
 108}
 109
 110/**
 111 * in4_pton - convert an IPv4 address from literal to binary representation
 112 * @src: the start of the IPv4 address string
 113 * @srclen: the length of the string, -1 means strlen(src)
 114 * @dst: the binary (u8[4] array) representation of the IPv4 address
 115 * @delim: the delimiter of the IPv4 address in @src, -1 means no delimiter
 116 * @end: A pointer to the end of the parsed string will be placed here
 117 *
 118 * Return one on success, return zero when any error occurs
 119 * and @end will point to the end of the parsed string.
 120 *
 121 */
 122int in4_pton(const char *src, int srclen,
 123             u8 *dst,
 124             int delim, const char **end)
 125{
 126        const char *s;
 127        u8 *d;
 128        u8 dbuf[4];
 129        int ret = 0;
 130        int i;
 131        int w = 0;
 132
 133        if (srclen < 0)
 134                srclen = strlen(src);
 135        s = src;
 136        d = dbuf;
 137        i = 0;
 138        while (1) {
 139                int c;
 140                c = xdigit2bin(srclen > 0 ? *s : '\0', delim);
 141                if (!(c & (IN6PTON_DIGIT | IN6PTON_DOT | IN6PTON_DELIM | IN6PTON_COLON_MASK))) {
 142                        goto out;
 143                }
 144                if (c & (IN6PTON_DOT | IN6PTON_DELIM | IN6PTON_COLON_MASK)) {
 145                        if (w == 0)
 146                                goto out;
 147                        *d++ = w & 0xff;
 148                        w = 0;
 149                        i++;
 150                        if (c & (IN6PTON_DELIM | IN6PTON_COLON_MASK)) {
 151                                if (i != 4)
 152                                        goto out;
 153                                break;
 154                        }
 155                        goto cont;
 156                }
 157                w = (w * 10) + c;
 158                if ((w & 0xffff) > 255) {
 159                        goto out;
 160                }
 161cont:
 162                if (i >= 4)
 163                        goto out;
 164                s++;
 165                srclen--;
 166        }
 167        ret = 1;
 168        memcpy(dst, dbuf, sizeof(dbuf));
 169out:
 170        if (end)
 171                *end = s;
 172        return ret;
 173}
 174EXPORT_SYMBOL(in4_pton);
 175
 176/**
 177 * in6_pton - convert an IPv6 address from literal to binary representation
 178 * @src: the start of the IPv6 address string
 179 * @srclen: the length of the string, -1 means strlen(src)
 180 * @dst: the binary (u8[16] array) representation of the IPv6 address
 181 * @delim: the delimiter of the IPv6 address in @src, -1 means no delimiter
 182 * @end: A pointer to the end of the parsed string will be placed here
 183 *
 184 * Return one on success, return zero when any error occurs
 185 * and @end will point to the end of the parsed string.
 186 *
 187 */
 188int in6_pton(const char *src, int srclen,
 189             u8 *dst,
 190             int delim, const char **end)
 191{
 192        const char *s, *tok = NULL;
 193        u8 *d, *dc = NULL;
 194        u8 dbuf[16];
 195        int ret = 0;
 196        int i;
 197        int state = IN6PTON_COLON_1_2 | IN6PTON_XDIGIT | IN6PTON_NULL;
 198        int w = 0;
 199
 200        memset(dbuf, 0, sizeof(dbuf));
 201
 202        s = src;
 203        d = dbuf;
 204        if (srclen < 0)
 205                srclen = strlen(src);
 206
 207        while (1) {
 208                int c;
 209
 210                c = xdigit2bin(srclen > 0 ? *s : '\0', delim);
 211                if (!(c & state))
 212                        goto out;
 213                if (c & (IN6PTON_DELIM | IN6PTON_COLON_MASK)) {
 214                        /* process one 16-bit word */
 215                        if (!(state & IN6PTON_NULL)) {
 216                                *d++ = (w >> 8) & 0xff;
 217                                *d++ = w & 0xff;
 218                        }
 219                        w = 0;
 220                        if (c & IN6PTON_DELIM) {
 221                                /* We've processed last word */
 222                                break;
 223                        }
 224                        /*
 225                         * COLON_1 => XDIGIT
 226                         * COLON_2 => XDIGIT|DELIM
 227                         * COLON_1_2 => COLON_2
 228                         */
 229                        switch (state & IN6PTON_COLON_MASK) {
 230                        case IN6PTON_COLON_2:
 231                                dc = d;
 232                                state = IN6PTON_XDIGIT | IN6PTON_DELIM;
 233                                if (dc - dbuf >= sizeof(dbuf))
 234                                        state |= IN6PTON_NULL;
 235                                break;
 236                        case IN6PTON_COLON_1|IN6PTON_COLON_1_2:
 237                                state = IN6PTON_XDIGIT | IN6PTON_COLON_2;
 238                                break;
 239                        case IN6PTON_COLON_1:
 240                                state = IN6PTON_XDIGIT;
 241                                break;
 242                        case IN6PTON_COLON_1_2:
 243                                state = IN6PTON_COLON_2;
 244                                break;
 245                        default:
 246                                state = 0;
 247                        }
 248                        tok = s + 1;
 249                        goto cont;
 250                }
 251
 252                if (c & IN6PTON_DOT) {
 253                        ret = in4_pton(tok ? tok : s, srclen + (int)(s - tok), d, delim, &s);
 254                        if (ret > 0) {
 255                                d += 4;
 256                                break;
 257                        }
 258                        goto out;
 259                }
 260
 261                w = (w << 4) | (0xff & c);
 262                state = IN6PTON_COLON_1 | IN6PTON_DELIM;
 263                if (!(w & 0xf000)) {
 264                        state |= IN6PTON_XDIGIT;
 265                }
 266                if (!dc && d + 2 < dbuf + sizeof(dbuf)) {
 267                        state |= IN6PTON_COLON_1_2;
 268                        state &= ~IN6PTON_DELIM;
 269                }
 270                if (d + 2 >= dbuf + sizeof(dbuf)) {
 271                        state &= ~(IN6PTON_COLON_1|IN6PTON_COLON_1_2);
 272                }
 273cont:
 274                if ((dc && d + 4 < dbuf + sizeof(dbuf)) ||
 275                    d + 4 == dbuf + sizeof(dbuf)) {
 276                        state |= IN6PTON_DOT;
 277                }
 278                if (d >= dbuf + sizeof(dbuf)) {
 279                        state &= ~(IN6PTON_XDIGIT|IN6PTON_COLON_MASK);
 280                }
 281                s++;
 282                srclen--;
 283        }
 284
 285        i = 15; d--;
 286
 287        if (dc) {
 288                while (d >= dc)
 289                        dst[i--] = *d--;
 290                while (i >= dc - dbuf)
 291                        dst[i--] = 0;
 292                while (i >= 0)
 293                        dst[i--] = *d--;
 294        } else
 295                memcpy(dst, dbuf, sizeof(dbuf));
 296
 297        ret = 1;
 298out:
 299        if (end)
 300                *end = s;
 301        return ret;
 302}
 303EXPORT_SYMBOL(in6_pton);
 304
 305static int inet4_pton(const char *src, u16 port_num,
 306                struct sockaddr_storage *addr)
 307{
 308        struct sockaddr_in *addr4 = (struct sockaddr_in *)addr;
 309        int srclen = strlen(src);
 310
 311        if (srclen > INET_ADDRSTRLEN)
 312                return -EINVAL;
 313
 314        if (in4_pton(src, srclen, (u8 *)&addr4->sin_addr.s_addr,
 315                     '\n', NULL) == 0)
 316                return -EINVAL;
 317
 318        addr4->sin_family = AF_INET;
 319        addr4->sin_port = htons(port_num);
 320
 321        return 0;
 322}
 323
 324static int inet6_pton(struct net *net, const char *src, u16 port_num,
 325                struct sockaddr_storage *addr)
 326{
 327        struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)addr;
 328        const char *scope_delim;
 329        int srclen = strlen(src);
 330
 331        if (srclen > INET6_ADDRSTRLEN)
 332                return -EINVAL;
 333
 334        if (in6_pton(src, srclen, (u8 *)&addr6->sin6_addr.s6_addr,
 335                     '%', &scope_delim) == 0)
 336                return -EINVAL;
 337
 338        if (ipv6_addr_type(&addr6->sin6_addr) & IPV6_ADDR_LINKLOCAL &&
 339            src + srclen != scope_delim && *scope_delim == '%') {
 340                struct net_device *dev;
 341                char scope_id[16];
 342                size_t scope_len = min_t(size_t, sizeof(scope_id) - 1,
 343                                         src + srclen - scope_delim - 1);
 344
 345                memcpy(scope_id, scope_delim + 1, scope_len);
 346                scope_id[scope_len] = '\0';
 347
 348                dev = dev_get_by_name(net, scope_id);
 349                if (dev) {
 350                        addr6->sin6_scope_id = dev->ifindex;
 351                        dev_put(dev);
 352                } else if (kstrtouint(scope_id, 0, &addr6->sin6_scope_id)) {
 353                        return -EINVAL;
 354                }
 355        }
 356
 357        addr6->sin6_family = AF_INET6;
 358        addr6->sin6_port = htons(port_num);
 359
 360        return 0;
 361}
 362
 363/**
 364 * inet_pton_with_scope - convert an IPv4/IPv6 and port to socket address
 365 * @net: net namespace (used for scope handling)
 366 * @af: address family, AF_INET, AF_INET6 or AF_UNSPEC for either
 367 * @src: the start of the address string
 368 * @port: the start of the port string (or NULL for none)
 369 * @addr: output socket address
 370 *
 371 * Return zero on success, return errno when any error occurs.
 372 */
 373int inet_pton_with_scope(struct net *net, __kernel_sa_family_t af,
 374                const char *src, const char *port, struct sockaddr_storage *addr)
 375{
 376        u16 port_num;
 377        int ret = -EINVAL;
 378
 379        if (port) {
 380                if (kstrtou16(port, 0, &port_num))
 381                        return -EINVAL;
 382        } else {
 383                port_num = 0;
 384        }
 385
 386        switch (af) {
 387        case AF_INET:
 388                ret = inet4_pton(src, port_num, addr);
 389                break;
 390        case AF_INET6:
 391                ret = inet6_pton(net, src, port_num, addr);
 392                break;
 393        case AF_UNSPEC:
 394                ret = inet4_pton(src, port_num, addr);
 395                if (ret)
 396                        ret = inet6_pton(net, src, port_num, addr);
 397                break;
 398        default:
 399                pr_err("unexpected address family %d\n", af);
 400        };
 401
 402        return ret;
 403}
 404EXPORT_SYMBOL(inet_pton_with_scope);
 405
 406void inet_proto_csum_replace4(__sum16 *sum, struct sk_buff *skb,
 407                              __be32 from, __be32 to, bool pseudohdr)
 408{
 409        if (skb->ip_summed != CHECKSUM_PARTIAL) {
 410                csum_replace4(sum, from, to);
 411                if (skb->ip_summed == CHECKSUM_COMPLETE && pseudohdr)
 412                        skb->csum = ~csum_add(csum_sub(~(skb->csum),
 413                                                       (__force __wsum)from),
 414                                              (__force __wsum)to);
 415        } else if (pseudohdr)
 416                *sum = ~csum_fold(csum_add(csum_sub(csum_unfold(*sum),
 417                                                    (__force __wsum)from),
 418                                           (__force __wsum)to));
 419}
 420EXPORT_SYMBOL(inet_proto_csum_replace4);
 421
 422void inet_proto_csum_replace16(__sum16 *sum, struct sk_buff *skb,
 423                               const __be32 *from, const __be32 *to,
 424                               bool pseudohdr)
 425{
 426        __be32 diff[] = {
 427                ~from[0], ~from[1], ~from[2], ~from[3],
 428                to[0], to[1], to[2], to[3],
 429        };
 430        if (skb->ip_summed != CHECKSUM_PARTIAL) {
 431                *sum = csum_fold(csum_partial(diff, sizeof(diff),
 432                                 ~csum_unfold(*sum)));
 433                if (skb->ip_summed == CHECKSUM_COMPLETE && pseudohdr)
 434                        skb->csum = ~csum_partial(diff, sizeof(diff),
 435                                                  ~skb->csum);
 436        } else if (pseudohdr)
 437                *sum = ~csum_fold(csum_partial(diff, sizeof(diff),
 438                                  csum_unfold(*sum)));
 439}
 440EXPORT_SYMBOL(inet_proto_csum_replace16);
 441
 442void inet_proto_csum_replace_by_diff(__sum16 *sum, struct sk_buff *skb,
 443                                     __wsum diff, bool pseudohdr)
 444{
 445        if (skb->ip_summed != CHECKSUM_PARTIAL) {
 446                *sum = csum_fold(csum_add(diff, ~csum_unfold(*sum)));
 447                if (skb->ip_summed == CHECKSUM_COMPLETE && pseudohdr)
 448                        skb->csum = ~csum_add(diff, ~skb->csum);
 449        } else if (pseudohdr) {
 450                *sum = ~csum_fold(csum_add(diff, csum_unfold(*sum)));
 451        }
 452}
 453EXPORT_SYMBOL(inet_proto_csum_replace_by_diff);
 454