Subversion Repositories planix.SVN

Rev

Blame | Last modification | View Log | RSS feed

#include <u.h>
#include <libc.h>
#include <ip.h>

enum
{
        Isprefix= 16,
};

uchar prefixvals[256] =
{
[0x00] 0 | Isprefix,
[0x80] 1 | Isprefix,
[0xC0] 2 | Isprefix,
[0xE0] 3 | Isprefix,
[0xF0] 4 | Isprefix,
[0xF8] 5 | Isprefix,
[0xFC] 6 | Isprefix,
[0xFE] 7 | Isprefix,
[0xFF] 8 | Isprefix,
};

int
eipfmt(Fmt *f)
{
        char buf[5*8];
        static char *efmt = "%.2ux%.2ux%.2ux%.2ux%.2ux%.2ux";
        static char *ifmt = "%d.%d.%d.%d";
        uchar *p, ip[16];
        ulong *lp;
        ushort s;
        int i, j, n, eln, eli;

        switch(f->r) {
        case 'E':               /* Ethernet address */
                p = va_arg(f->args, uchar*);
                snprint(buf, sizeof buf, efmt, p[0], p[1], p[2], p[3], p[4], p[5]);
                return fmtstrcpy(f, buf);

        case 'I':               /* Ip address */
                p = va_arg(f->args, uchar*);
common:
                if(memcmp(p, v4prefix, 12) == 0){
                        snprint(buf, sizeof buf, ifmt, p[12], p[13], p[14], p[15]);
                        return fmtstrcpy(f, buf);
                }

                /* find longest elision */
                eln = eli = -1;
                for(i = 0; i < 16; i += 2){
                        for(j = i; j < 16; j += 2)
                                if(p[j] != 0 || p[j+1] != 0)
                                        break;
                        if(j > i && j - i > eln){
                                eli = i;
                                eln = j - i;
                        }
                }

                /* print with possible elision */
                n = 0;
                for(i = 0; i < 16; i += 2){
                        if(i == eli){
                                n += sprint(buf+n, "::");
                                i += eln;
                                if(i >= 16)
                                        break;
                        } else if(i != 0)
                                n += sprint(buf+n, ":");
                        s = (p[i]<<8) + p[i+1];
                        n += sprint(buf+n, "%ux", s);
                }
                return fmtstrcpy(f, buf);

        case 'i':               /* v6 address as 4 longs */
                lp = va_arg(f->args, ulong*);
                for(i = 0; i < 4; i++)
                        hnputl(ip+4*i, *lp++);
                p = ip;
                goto common;

        case 'V':               /* v4 ip address */
                p = va_arg(f->args, uchar*);
                snprint(buf, sizeof buf, ifmt, p[0], p[1], p[2], p[3]);
                return fmtstrcpy(f, buf);

        case 'M':               /* ip mask */
                p = va_arg(f->args, uchar*);

                /* look for a prefix mask */
                for(i = 0; i < 16; i++)
                        if(p[i] != 0xff)
                                break;
                if(i < 16){
                        if((prefixvals[p[i]] & Isprefix) == 0)
                                goto common;
                        for(j = i+1; j < 16; j++)
                                if(p[j] != 0)
                                        goto common;
                        n = 8*i + (prefixvals[p[i]] & ~Isprefix);
                } else
                        n = 8*16;

                /* got one, use /xx format */
                snprint(buf, sizeof buf, "/%d", n);
                return fmtstrcpy(f, buf);
        }
        return fmtstrcpy(f, "(eipfmt)");
}