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