xref: /dragonfly/lib/libc/net/linkaddr.c (revision 02318f07)
1 /*-
2  * Copyright (c) 1990, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the University nor the names of its contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * @(#)linkaddr.c	8.1 (Berkeley) 6/4/93
30  * $FreeBSD: src/lib/libc/net/linkaddr.c,v 1.4 2007/01/09 00:28:02 imp Exp $
31  * $DragonFly: src/lib/libc/net/linkaddr.c,v 1.5 2005/11/13 02:04:47 swildner Exp $
32  */
33 
34 #include <sys/types.h>
35 #include <sys/socket.h>
36 #include <net/if.h>
37 #include <net/if_dl.h>
38 #include <string.h>
39 
40 /* States*/
41 #define NAMING	0
42 #define GOTONE	1
43 #define GOTTWO	2
44 #define RESET	3
45 /* Inputs */
46 #define	DIGIT	(4*0)
47 #define	END	(4*1)
48 #define DELIM	(4*2)
49 #define LETTER	(4*3)
50 
51 void
52 link_addr(const char *addr, struct sockaddr_dl *sdl)
53 {
54 	char *cp = sdl->sdl_data;
55 	char *cplim = sdl->sdl_len + (char *)sdl;
56 	int byte = 0, state = NAMING, new;
57 
58 	bzero((char *)&sdl->sdl_family, sdl->sdl_len - 1);
59 	sdl->sdl_family = AF_LINK;
60 	do {
61 		state &= ~LETTER;
62 		if ((*addr >= '0') && (*addr <= '9')) {
63 			new = *addr - '0';
64 		} else if ((*addr >= 'a') && (*addr <= 'f')) {
65 			new = *addr - 'a' + 10;
66 		} else if ((*addr >= 'A') && (*addr <= 'F')) {
67 			new = *addr - 'A' + 10;
68 		} else if (*addr == 0) {
69 			state |= END;
70 		} else if (state == NAMING &&
71 			   (((*addr >= 'A') && (*addr <= 'Z')) ||
72 			   ((*addr >= 'a') && (*addr <= 'z'))))
73 			state |= LETTER;
74 		else
75 			state |= DELIM;
76 		addr++;
77 		switch (state /* | INPUT */) {
78 		case NAMING | DIGIT:
79 		case NAMING | LETTER:
80 			*cp++ = addr[-1];
81 			continue;
82 		case NAMING | DELIM:
83 			state = RESET;
84 			sdl->sdl_nlen = cp - sdl->sdl_data;
85 			continue;
86 		case GOTTWO | DIGIT:
87 			*cp++ = byte;
88 			/* FALLTHROUGH */
89 		case RESET | DIGIT:
90 			state = GOTONE;
91 			byte = new;
92 			continue;
93 		case GOTONE | DIGIT:
94 			state = GOTTWO;
95 			byte = new + (byte << 4);
96 			continue;
97 		default: /* | DELIM */
98 			state = RESET;
99 			*cp++ = byte;
100 			byte = 0;
101 			continue;
102 		case GOTONE | END:
103 		case GOTTWO | END:
104 			*cp++ = byte;
105 			/* FALLTHROUGH */
106 		case RESET | END:
107 			break;
108 		}
109 		break;
110 	} while (cp < cplim);
111 	sdl->sdl_alen = cp - LLADDR(sdl);
112 	new = cp - (char *)sdl;
113 	if (new > sizeof(*sdl))
114 		sdl->sdl_len = new;
115 	return;
116 }
117 
118 static char hexlist[] = "0123456789abcdef";
119 
120 char *
121 link_ntoa(const struct sockaddr_dl *sdl)
122 {
123 	static char obuf[64];
124 	_Static_assert(sizeof(obuf) >= IFNAMSIZ + 20, "obuf is too small");
125 	char *out;
126 	const char *in, *inlim;
127 	int namelen, i, rem;
128 
129 	namelen = (sdl->sdl_nlen <= IFNAMSIZ) ? sdl->sdl_nlen : IFNAMSIZ;
130 
131 	out = obuf;
132 	rem = sizeof(obuf);
133 	if (namelen > 0) {
134 		bcopy(sdl->sdl_data, out, namelen);
135 		out += namelen;
136 		rem -= namelen;
137 		if (sdl->sdl_alen > 0) {
138 			*out++ = ':';
139 			rem--;
140 		}
141 	}
142 
143 	in = (const char *)sdl->sdl_data + sdl->sdl_nlen;
144 	inlim = in + sdl->sdl_alen;
145 
146 	while (in < inlim && rem > 1) {
147 		if (in != (const char *)sdl->sdl_data + sdl->sdl_nlen) {
148 			*out++ = '.';
149 			rem--;
150 		}
151 		i = *in++;
152 		if (i > 0xf) {
153 			if (rem < 3)
154 				break;
155 			*out++ = hexlist[i & 0xf];
156 			i >>= 4;
157 			*out++ = hexlist[i];
158 			rem -= 2;
159 		} else {
160 			if (rem < 2)
161 				break;
162 			*out++ = hexlist[i];
163 			rem++;
164 		}
165 	}
166 	*out = 0;
167 	return (obuf);
168 }
169