#include #include #include enum { Isprefix= 16 }; /* XXX: manually initialize once to placate the Sun monster */ uchar prefixvals[256]; #ifdef NOTDEF 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, }; #endif int eipfmt(Fmt *f) { char buf[5*8]; static char *efmt = "%.2ux%.2ux%.2ux%.2ux%.2ux%.2ux"; static char *altefmt = "%.2ux:%.2ux:%.2ux:%.2ux:%.2ux:%.2ux"; static char *ifmt = "%d.%d.%d.%d"; char *fmt; uchar *p, ip[16]; ulong *lp; ushort s; int i, j, n, eln, eli; static int once = 0; /* XXX: placate the Sun monster */ if(!once){ once = 1; memset(prefixvals, 0, sizeof(prefixvals)); prefixvals[0x00] = 0 | Isprefix; prefixvals[0x80] = 1 | Isprefix; prefixvals[0xC0] = 2 | Isprefix; prefixvals[0xE0] = 3 | Isprefix; prefixvals[0xF0] = 4 | Isprefix; prefixvals[0xF8] = 5 | Isprefix; prefixvals[0xFC] = 6 | Isprefix; prefixvals[0xFE] = 7 | Isprefix; prefixvals[0xFF] = 8 | Isprefix; } switch(f->r) { case 'E': /* Ethernet address */ p = va_arg(f->args, uchar*); fmt = efmt; if(f->flags&FmtSharp) fmt = altefmt; snprint(buf, sizeof buf, fmt, 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)"); }