eipfmt.c 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <ip.h>
  4. enum
  5. {
  6. Isprefix= 16,
  7. };
  8. uchar prefixvals[256] =
  9. {
  10. [0x00] 0 | Isprefix,
  11. [0x80] 1 | Isprefix,
  12. [0xC0] 2 | Isprefix,
  13. [0xE0] 3 | Isprefix,
  14. [0xF0] 4 | Isprefix,
  15. [0xF8] 5 | Isprefix,
  16. [0xFC] 6 | Isprefix,
  17. [0xFE] 7 | Isprefix,
  18. [0xFF] 8 | Isprefix,
  19. };
  20. int
  21. eipfmt(Fmt *f)
  22. {
  23. char buf[5*8];
  24. static char *efmt = "%.2ux%.2ux%.2ux%.2ux%.2ux%.2ux";
  25. static char *ifmt = "%d.%d.%d.%d";
  26. uchar *p, ip[16];
  27. ulong *lp;
  28. ushort s;
  29. int i, j, n, eln, eli;
  30. switch(f->r) {
  31. case 'E': /* Ethernet address */
  32. p = va_arg(f->args, uchar*);
  33. snprint(buf, sizeof buf, efmt, p[0], p[1], p[2], p[3], p[4], p[5]);
  34. return fmtstrcpy(f, buf);
  35. case 'I': /* Ip address */
  36. p = va_arg(f->args, uchar*);
  37. common:
  38. if(memcmp(p, v4prefix, 12) == 0){
  39. snprint(buf, sizeof buf, ifmt, p[12], p[13], p[14], p[15]);
  40. return fmtstrcpy(f, buf);
  41. }
  42. /* find longest elision */
  43. eln = eli = -1;
  44. for(i = 0; i < 16; i += 2){
  45. for(j = i; j < 16; j += 2)
  46. if(p[j] != 0 || p[j+1] != 0)
  47. break;
  48. if(j > i && j - i > eln){
  49. eli = i;
  50. eln = j - i;
  51. }
  52. }
  53. /* print with possible elision */
  54. n = 0;
  55. for(i = 0; i < 16; i += 2){
  56. if(i == eli){
  57. n += sprint(buf+n, "::");
  58. i += eln;
  59. if(i >= 16)
  60. break;
  61. } else if(i != 0)
  62. n += sprint(buf+n, ":");
  63. s = (p[i]<<8) + p[i+1];
  64. n += sprint(buf+n, "%ux", s);
  65. }
  66. return fmtstrcpy(f, buf);
  67. case 'i': /* v6 address as 4 longs */
  68. lp = va_arg(f->args, ulong*);
  69. for(i = 0; i < 4; i++)
  70. hnputl(ip+4*i, *lp++);
  71. p = ip;
  72. goto common;
  73. case 'V': /* v4 ip address */
  74. p = va_arg(f->args, uchar*);
  75. snprint(buf, sizeof buf, ifmt, p[0], p[1], p[2], p[3]);
  76. return fmtstrcpy(f, buf);
  77. case 'M': /* ip mask */
  78. p = va_arg(f->args, uchar*);
  79. /* look for a prefix mask */
  80. for(i = 0; i < 16; i++)
  81. if(p[i] != 0xff)
  82. break;
  83. if(i < 16){
  84. if((prefixvals[p[i]] & Isprefix) == 0)
  85. goto common;
  86. for(j = i+1; j < 16; j++)
  87. if(p[j] != 0)
  88. goto common;
  89. n = 8*i + (prefixvals[p[i]] & ~Isprefix);
  90. } else
  91. n = 8*16;
  92. /* got one, use /xx format */
  93. snprint(buf, sizeof buf, "/%d", n);
  94. return fmtstrcpy(f, buf);
  95. }
  96. return fmtstrcpy(f, "(eipfmt)");
  97. }