xref: /inferno-os/os/ip/eipconvtest.c (revision 7ef44d652ae9e5e1f5b3465d73684e4a54de73c0)
1 #include <u.h>
2 #include <libc.h>
3 
4 enum
5 {
6 	Isprefix= 16,
7 };
8 
9 uchar prefixvals[256] =
10 {
11 [0x00] 0 | Isprefix,
12 [0x80] 1 | Isprefix,
13 [0xC0] 2 | Isprefix,
14 [0xE0] 3 | Isprefix,
15 [0xF0] 4 | Isprefix,
16 [0xF8] 5 | Isprefix,
17 [0xFC] 6 | Isprefix,
18 [0xFE] 7 | Isprefix,
19 [0xFF] 8 | Isprefix,
20 };
21 
22 uchar v4prefix[16] = {
23 	0, 0, 0, 0,
24 	0, 0, 0, 0,
25 	0, 0, 0xff, 0xff,
26 	0, 0, 0, 0
27 };
28 
29 void
30 hnputl(void *p, ulong v)
31 {
32 	uchar *a;
33 
34 	a = p;
35 	a[0] = v>>24;
36 	a[1] = v>>16;
37 	a[2] = v>>8;
38 	a[3] = v;
39 }
40 
41 int
42 eipconv(va_list *arg, Fconv *f)
43 {
44 	char buf[8*5];
45 	static char *efmt = "%.2lux%.2lux%.2lux%.2lux%.2lux%.2lux";
46 	static char *ifmt = "%d.%d.%d.%d";
47 	uchar *p, ip[16];
48 	ulong *lp;
49 	ushort s;
50 	int i, j, n, eln, eli;
51 
52 	switch(f->chr) {
53 	case 'E':		/* Ethernet address */
54 		p = va_arg(*arg, uchar*);
55 		sprint(buf, efmt, p[0], p[1], p[2], p[3], p[4], p[5]);
56 		break;
57 	case 'I':		/* Ip address */
58 		p = va_arg(*arg, uchar*);
59 common:
60 		if(memcmp(p, v4prefix, 12) == 0)
61 			sprint(buf, ifmt, p[12], p[13], p[14], p[15]);
62 		else {
63 			/* find longest elision */
64 			eln = eli = -1;
65 			for(i = 0; i < 16; i += 2){
66 				for(j = i; j < 16; j += 2)
67 					if(p[j] != 0 || p[j+1] != 0)
68 						break;
69 				if(j > i && j - i > eln){
70 					eli = i;
71 					eln = j - i;
72 				}
73 			}
74 
75 			/* print with possible elision */
76 			n = 0;
77 			for(i = 0; i < 16; i += 2){
78 				if(i == eli){
79 					n += sprint(buf+n, "::");
80 					i += eln;
81 					if(i >= 16)
82 						break;
83 				} else if(i != 0)
84 					n += sprint(buf+n, ":");
85 				s = (p[i]<<8) + p[i+1];
86 				n += sprint(buf+n, "%ux", s);
87 			}
88 		}
89 		break;
90 	case 'i':		/* v6 address as 4 longs */
91 		lp = va_arg(*arg, ulong*);
92 		for(i = 0; i < 4; i++)
93 			hnputl(ip+4*i, *lp++);
94 		p = ip;
95 		goto common;
96 	case 'V':		/* v4 ip address */
97 		p = va_arg(*arg, uchar*);
98 		sprint(buf, ifmt, p[0], p[1], p[2], p[3]);
99 		break;
100 	case 'M':		/* ip mask */
101 		p = va_arg(*arg, uchar*);
102 
103 		/* look for a prefix mask */
104 		for(i = 0; i < 16; i++)
105 			if(p[i] != 0xff)
106 				break;
107 		if(i < 16){
108 			if((prefixvals[p[i]] & Isprefix) == 0)
109 				goto common;
110 			for(j = i+1; j < 16; j++)
111 				if(p[j] != 0)
112 					goto common;
113 			n = 8*i + (prefixvals[p[i]] & ~Isprefix);
114 		} else
115 			n = 8*16;
116 
117 		/* got one, use /xx format */
118 		sprint(buf, "/%d", n);
119 		break;
120 	default:
121 		strcpy(buf, "(eipconv)");
122 	}
123 	strconv(buf, f);
124 	return sizeof(uchar*);
125 }
126 
127 uchar testvec[11][16] =
128 {
129  { 0,0,0,0, 0,0,0,0, 0,0,0xff,0xff, 1,3,4,5, },
130  { 0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff, },
131  { 0xff,0xff,0x80,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, },
132  { 0xff,0xff,0xff,0xc0, 0,0,0,0, 0,0,0,0, 0,0,0,0, },
133  { 0xff,0xff,0xff,0xff, 0xe0,0,0,0, 0,0,0,0, 0,0,0,0, },
134  { 0xff,0xff,0xff,0xff, 0xff,0xf0,0,0, 0,0,0,0, 0,0,0,0, },
135  { 0xff,0xff,0xff,0xff, 0xff,0xff,0xf8,0, 0,0,0,0, 0,0,0,0, },
136  { 0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff, },
137  { 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, },
138  { 0,0,0,0, 0,0x11,0,0, 0,0,0,0, 0,0,0,0, },
139  { 0,0,0,0x11, 0,0,0,0, 0,0,0,0, 0,0,0,0x12, },
140 };
141 
142 void
143 main(void)
144 {
145 	int i;
146 
147 	fmtinstall('I', eipconv);
148 	fmtinstall('M', eipconv);
149 	for(i = 0; i < 11; i++)
150 		print("%I\n%M\n", testvec[i], testvec[i]);
151 	exits(0);
152 }
153