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/inet.h>
  21#include <linux/mm.h>
  22#include <linux/net.h>
  23#include <linux/string.h>
  24#include <linux/types.h>
  25#include <linux/percpu.h>
  26#include <linux/init.h>
  27#include <linux/ratelimit.h>
  28
  29#include <net/sock.h>
  30#include <net/net_ratelimit.h>
  31
  32#include <asm/byteorder.h>
  33#include <asm/uaccess.h>
  34
  35int net_msg_warn __read_mostly = 1;
  36EXPORT_SYMBOL(net_msg_warn);
  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 long 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
 305void inet_proto_csum_replace4(__sum16 *sum, struct sk_buff *skb,
 306                              __be32 from, __be32 to, int pseudohdr)
 307{
 308        __be32 diff[] = { ~from, to };
 309        if (skb->ip_summed != CHECKSUM_PARTIAL) {
 310                *sum = csum_fold(csum_partial(diff, sizeof(diff),
 311                                ~csum_unfold(*sum)));
 312                if (skb->ip_summed == CHECKSUM_COMPLETE && pseudohdr)
 313                        skb->csum = ~csum_partial(diff, sizeof(diff),
 314                                                ~skb->csum);
 315        } else if (pseudohdr)
 316                *sum = ~csum_fold(csum_partial(diff, sizeof(diff),
 317                                csum_unfold(*sum)));
 318}
 319EXPORT_SYMBOL(inet_proto_csum_replace4);
 320
 321void inet_proto_csum_replace16(__sum16 *sum, struct sk_buff *skb,
 322                               const __be32 *from, const __be32 *to,
 323                               int pseudohdr)
 324{
 325        __be32 diff[] = {
 326                ~from[0], ~from[1], ~from[2], ~from[3],
 327                to[0], to[1], to[2], to[3],
 328        };
 329        if (skb->ip_summed != CHECKSUM_PARTIAL) {
 330                *sum = csum_fold(csum_partial(diff, sizeof(diff),
 331                                 ~csum_unfold(*sum)));
 332                if (skb->ip_summed == CHECKSUM_COMPLETE && pseudohdr)
 333                        skb->csum = ~csum_partial(diff, sizeof(diff),
 334                                                  ~skb->csum);
 335        } else if (pseudohdr)
 336                *sum = ~csum_fold(csum_partial(diff, sizeof(diff),
 337                                  csum_unfold(*sum)));
 338}
 339EXPORT_SYMBOL(inet_proto_csum_replace16);
 340
 341int mac_pton(const char *s, u8 *mac)
 342{
 343        int i;
 344
 345        /* XX:XX:XX:XX:XX:XX */
 346        if (strlen(s) < 3 * ETH_ALEN - 1)
 347                return 0;
 348
 349        /* Don't dirty result unless string is valid MAC. */
 350        for (i = 0; i < ETH_ALEN; i++) {
 351                if (!strchr("0123456789abcdefABCDEF", s[i * 3]))
 352                        return 0;
 353                if (!strchr("0123456789abcdefABCDEF", s[i * 3 + 1]))
 354                        return 0;
 355                if (i != ETH_ALEN - 1 && s[i * 3 + 2] != ':')
 356                        return 0;
 357        }
 358        for (i = 0; i < ETH_ALEN; i++) {
 359                mac[i] = (hex_to_bin(s[i * 3]) << 4) | hex_to_bin(s[i * 3 + 1]);
 360        }
 361        return 1;
 362}
 363EXPORT_SYMBOL(mac_pton);
 364
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.