xref: /plan9/sys/src/cmd/ip/linklocal.c (revision 14cc0f535177405a84c5b73603a98e5db6674719)
1 /*
2  * linklocal - print ipv6 link-local or 6to4 address of a mac address.
3  * eui is ieee's extended unique identifier, per rfc2373.
4  */
5 
6 #include <u.h>
7 #include <libc.h>
8 #include <ip.h>
9 
10 enum {
11 	Mac0mcast	= 1<<0,		/* multicast address */
12 	Mac0localadm	= 1<<1,		/* locally-administered address, */
13 	V60globaladm	= 1<<1,		/* but ipv6 reverses the meaning */
14 };
15 
16 static char *v4_6to4;
17 
18 static void
usage(void)19 usage(void)
20 {
21 	fprint(2, "usage: %s [-t ipv4] ether...\n", argv0);
22 	exits("usage");
23 }
24 
25 void
ea2eui64(uchar * lla,uchar * ea)26 ea2eui64(uchar *lla, uchar *ea)
27 {
28 	*lla++ = *ea++ | V60globaladm;	/* oui (company id) */
29 	*lla++ = *ea++;			/* " */
30 	*lla++ = *ea++;			/* " */
31 	*lla++ = 0xFF;			/* mac-48 in eui-64 (sic) */
32 	*lla++ = 0xFE;			/* " */
33 	*lla++ = *ea++;			/* manufacturer-assigned */
34 	*lla++ = *ea++;			/* " */
35 	*lla = *ea;			/* " */
36 }
37 
38 void
eaip26to4(uchar * lla,uchar * ea,uchar * ipv4)39 eaip26to4(uchar *lla, uchar *ea, uchar *ipv4)
40 {
41 	*lla++ = 0x20;			/* 6to4 address */
42 	*lla++ = 0x02;			/* " */
43 	memmove(lla, ipv4, IPv4addrlen);
44 	lla += IPv4addrlen;
45 	memset(lla, 0, 2);
46 	ea2eui64(lla + 2, ea);
47 }
48 
49 void
ea2lla(uchar * lla,uchar * ea)50 ea2lla(uchar *lla, uchar *ea)
51 {
52 	*lla++ = 0xFE;			/* link-local v6 */
53 	*lla++ = 0x80;			/* " */
54 	memset(lla, 0, 6);
55 	ea2eui64(lla + 6, ea);
56 }
57 
58 static void
process(char * ether)59 process(char *ether)
60 {
61 	uchar ethaddr[6], ipaddr[IPaddrlen], ipv4[IPv4addrlen];
62 
63 	if (parseether(ethaddr, ether) < 0)
64 		sysfatal("%s: not an ether address", ether);
65 	if (v4_6to4) {
66 		v4parseip(ipv4, v4_6to4);
67 		eaip26to4(ipaddr, ethaddr, ipv4);
68 	} else
69 		ea2lla(ipaddr, ethaddr);
70 	print("%I\n", ipaddr);
71 }
72 
73 void
main(int argc,char * argv[])74 main(int argc, char *argv[])
75 {
76 	int i;
77 
78 	ARGBEGIN {
79 	case 't':
80 		v4_6to4 = EARGF(usage());
81 		break;
82 	default:
83 		usage();
84 		break;
85 	} ARGEND
86 
87 	fmtinstall('I', eipfmt);
88 	if (argc <= 0)
89 		usage();
90 
91 	for (i = 0; i < argc; i++)
92 		process(argv[i]);
93 	exits(0);
94 }
95