【Atheros】pktgen的ipv6地址处理函数参考及ipv6基本知识

pktgen有很多函数可以作为很好的网络相关的工具函数,这里列出ipv6中1:0:0:0:0:0:0:1和1::1这两种地址形式相互转化的工具函数。

第一个函数,用于把一个1:0:0:0:0:0:0:1形式的地址转化为1::1

/*
 * scan_ip6, fmt_ip taken from dietlibc-0.21
 * Author Felix von Leitner <felix-dietlibc@fefe.de>
 *
 * Slightly modified for kernel.
 * Should be candidate for net/ipv4/utils.c
 * --ro
 */

static unsigned int scan_ip6(const char *s, char ip[16])
{
    unsigned int i;
    unsigned int len = 0;
    unsigned long u;
    char suffix[16];
    unsigned int prefixlen = 0;
    unsigned int suffixlen = 0;
    __be32 tmp;
    char *pos;

    for (i = 0; i < 16; i++)
        ip[i] = 0;

    for (;;) {
        if (*s == ':') {
            len++;
            if (s[1] == ':') {    /* Found "::", skip to part 2 */
                s += 2;
                len++;
                break;
            }
            s++;
        }

        u = simple_strtoul(s, &pos, 16);
        i = pos - s;
        if (!i)
            return 0;
        if (prefixlen == 12 && s[i] == '.') {

            /* the last 4 bytes may be written as IPv4 address */

            tmp = in_aton(s);
            memcpy((struct in_addr *)(ip + 12), &tmp, sizeof(tmp));
            return i + len;
        }
        ip[prefixlen++] = (u >> 8);
        ip[prefixlen++] = (u & 255);
        s += i;
        len += i;
        if (prefixlen == 16)
            return len;
    }

/* part 2, after "::" */
    for (;;) {
        if (*s == ':') {
            if (suffixlen == 0)
                break;
            s++;
            len++;
        } else if (suffixlen != 0)
            break;

        u = simple_strtol(s, &pos, 16);
        i = pos - s;
        if (!i) {
            if (*s)
                len--;
            break;
        }
        if (suffixlen + prefixlen <= 12 && s[i] == '.') {
            tmp = in_aton(s);
            memcpy((struct in_addr *)(suffix + suffixlen), &tmp,
                   sizeof(tmp));
            suffixlen += 4;
            len += strlen(s);
            break;
        }
        suffix[suffixlen++] = (u >> 8);
        suffix[suffixlen++] = (u & 255);
        s += i;
        len += i;
        if (prefixlen + suffixlen == 16)
            break;
    }
    for (i = 0; i < suffixlen; i++)
        ip[16 - suffixlen + i] = suffix[i];
    return len;
}

第二个函数完成反向的转换,把1::1恢复成完成的地址:

static unsigned int fmt_ip6(char *s, const char ip[16])
{
    unsigned int len;
    unsigned int i;
    unsigned int temp;
    unsigned int compressing;
    int j;

    len = 0;
    compressing = 0;
    for (j = 0; j < 16; j += 2) {

#ifdef V4MAPPEDPREFIX
        if (j == 12 && !memcmp(ip, V4mappedprefix, 12)) {
            inet_ntoa_r(*(struct in_addr *)(ip + 12), s);
            temp = strlen(s);
            return len + temp;
        }
#endif
        temp = ((unsigned long)(unsigned char)ip[j] << 8) +
            (unsigned long)(unsigned char)ip[j + 1];
        if (temp == 0) {
            if (!compressing) {
                compressing = 1;
                if (j == 0) {
                    *s++ = ':';
                    ++len;
                }
            }
        } else {
            if (compressing) {
                compressing = 0;
                *s++ = ':';
                ++len;
            }
            i = fmt_xlong(s, temp);
            len += i;
            s += i;
            if (j < 14) {
                *s++ = ':';
                ++len;
            }
        }
    }
    if (compressing) {
        *s++ = ':';
        ++len;
    }
    *s = 0;
    return len;
}

 

下面附上ipv6的一些相关的基础知识,看懂这些也更有助于理解上面的两个函数,ps:这好像是我之前在一些网站上截的,我当时也记了源地址,但是源网站已经挂掉了:

IPv4地址是类似 A.B.C.D 的格式,它是32位,用.分成四段,用10进制表示;而IPv6地址类似X:X:X:X:X:X:X:X的格式,它是128位的,用:分 成8段,用16进制表示,每一段的值从8位扩充到16位。

RFC2373 中定义了完整的IPv6地址表示:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx

例如: 2001:0000: 1F 1F :0000:0000:0100: 11A 0:ADDF

为简化表示, rfc2373提出每段中前面的0可以省略,连续的0可省略为::,但只能出现一次。例如:

1080:0:0:0:8:800: 200C : 417A 可简写为 1080::8:800: 200C : 417A

FF01:0:0:0:0:0:0:101 可简写为 FF01::101

0:0:0:0:0:0:0:1 可简写为 ::1

0:0:0:0:0:0:0:0 可简写为 ::

这里给出一个表格,以比较IPv4和IPv6地址对应关系和区别。

IPv4

IPv6

组播地址(224.0.0.0/4)

IPv6组播地址(FF00::/8)

有广播地址

无广播,只有任播(anycast)

未指定地址为 0.0.0 .0

未指定地址为 ::

回路地址为 127.0.0.1

回路地址为 ::1

私有地址( 10.0.0 .0/8、172.16.0.0/12和192.168.0.0/16)

本地站点地址( FEC0::/48)

Microsoft自动专用IP寻址自动配置的地址(169.254.0.0/16)

本地链路地址( FE80::/64)

表达方式:点分十进制

表达方式:冒号十六进制式

子网掩码表示:以点阵十进制表示法或前缀长度表示法( CIDR)

子网掩码表示:仅使用前缀长度表示法( CIDR)

常见的IPv6地址及其前缀:

::/128  即0:0:0:0:0:0:0:0,只能作为尚未获得正式地址的主机的源地址,不能作为目的地址,不能分配给真实的网络接口。

::1/128 即0:0:0:0:0:0:0:1,回环地址,相当于IPv4中的localhost(127.0.0.1),ping locahost可得到此地址。

2001::/16  全球可聚合地址,由 IANA 按地域和ISP进行分配,是最常用的IPv6地址,属于单播地址。

2002::/16  6 to 4 地址,用于6to4自动构造隧道技术的地址,属于单播地址。

3ffe::/16   早期开始的IPv6 6bone试验网 地址,属于单播地址。

fe80::/10   本地链路地址,用于单一链路,适用于自动配置、邻机发现等,路由器不转发以fe80开头的地址。

ff00::/8  组播地址。

::A.B.C.D  兼容IPv4的IPv6地址,其中<A.B.C.D>代表IPv4地址。自动将IPv6包以隧道方式在IPv4网络中传送的IPv4/IPv6节点将使用这些地址。

::FFFF:A.B.C.D   是IPv4映射过来的IPv6地址,其中<A.B.C.D>代表IPv4地址,例如 ::ffff:202.120.2.30 ,它是在不支持IPv6的网上用于表示IPv4节点。

posted @ 2014-11-12 21:06  琴剑飘零  阅读(752)  评论(0编辑  收藏  举报