Subversion Repositories planix.SVN

Rev

Blame | Last modification | View Log | RSS feed

#include <u.h>
#include <libc.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,
};

uchar v4prefix[16] = {
        0, 0, 0, 0,
        0, 0, 0, 0,
        0, 0, 0xff, 0xff,
        0, 0, 0, 0
};

void
hnputl(void *p, ulong v)
{
        uchar *a;

        a = p;
        a[0] = v>>24;
        a[1] = v>>16;
        a[2] = v>>8;
        a[3] = v;
}

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

        switch(f->chr) {
        case 'E':               /* Ethernet address */
                p = va_arg(*arg, uchar*);
                sprint(buf, efmt, p[0], p[1], p[2], p[3], p[4], p[5]);
                break;
        case 'I':               /* Ip address */
                p = va_arg(*arg, uchar*);
common:
                if(memcmp(p, v4prefix, 12) == 0)
                        sprint(buf, ifmt, p[12], p[13], p[14], p[15]);
                else {
                        /* 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);
                        }
                }
                break;
        case 'i':               /* v6 address as 4 longs */
                lp = va_arg(*arg, ulong*);
                for(i = 0; i < 4; i++)
                        hnputl(ip+4*i, *lp++);
                p = ip;
                goto common;
        case 'V':               /* v4 ip address */
                p = va_arg(*arg, uchar*);
                sprint(buf, ifmt, p[0], p[1], p[2], p[3]);
                break;
        case 'M':               /* ip mask */
                p = va_arg(*arg, 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 */
                sprint(buf, "/%d", n);
                break;
        default:
                strcpy(buf, "(eipconv)");
        }
        strconv(buf, f);
        return sizeof(uchar*);
}

uchar testvec[11][16] =
{
 { 0,0,0,0, 0,0,0,0, 0,0,0xff,0xff, 1,3,4,5, },
 { 0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff, },
 { 0xff,0xff,0x80,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, },
 { 0xff,0xff,0xff,0xc0, 0,0,0,0, 0,0,0,0, 0,0,0,0, },
 { 0xff,0xff,0xff,0xff, 0xe0,0,0,0, 0,0,0,0, 0,0,0,0, },
 { 0xff,0xff,0xff,0xff, 0xff,0xf0,0,0, 0,0,0,0, 0,0,0,0, },
 { 0xff,0xff,0xff,0xff, 0xff,0xff,0xf8,0, 0,0,0,0, 0,0,0,0, },
 { 0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff, },
 { 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, },
 { 0,0,0,0, 0,0x11,0,0, 0,0,0,0, 0,0,0,0, },
 { 0,0,0,0x11, 0,0,0,0, 0,0,0,0, 0,0,0,0x12, },
};

void
main(void)
{
        int i;

        fmtinstall('I', eipconv);
        fmtinstall('M', eipconv);
        for(i = 0; i < 11; i++)
                print("%I\n%M\n", testvec[i], testvec[i]);
        exits(0);
}