149884Ssheldonh/*-
249884Ssheldonh * Copyright (c) 1990, 1993
349884Ssheldonh *	The Regents of the University of California.  All rights reserved.
449884Ssheldonh *
549884Ssheldonh * Redistribution and use in source and binary forms, with or without
649884Ssheldonh * modification, are permitted provided that the following conditions
749884Ssheldonh * are met:
849884Ssheldonh * 1. Redistributions of source code must retain the above copyright
91556Srgrimes *    notice, this list of conditions and the following disclaimer.
1049884Ssheldonh * 2. Redistributions in binary form must reproduce the above copyright
111556Srgrimes *    notice, this list of conditions and the following disclaimer in the
121556Srgrimes *    documentation and/or other materials provided with the distribution.
131556Srgrimes * 4. Neither the name of the University nor the names of its contributors
1436152Scharnier *    may be used to endorse or promote products derived from this software
1550471Speter *    without specific prior written permission.
161556Srgrimes *
171556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
1849884Ssheldonh * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
191556Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
201556Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
211556Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
221556Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
231556Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2493345Sache * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2576883Skris * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2686619Sknu * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
271556Srgrimes * SUCH DAMAGE.
281556Srgrimes */
291556Srgrimes
301556Srgrimes#if defined(LIBC_SCCS) && !defined(lint)
311556Srgrimesstatic char sccsid[] = "@(#)linkaddr.c	8.1 (Berkeley) 6/4/93";
3286505Sknu#endif /* LIBC_SCCS and not lint */
3386505Sknu#include <sys/cdefs.h>
3486505Sknu__FBSDID("$FreeBSD: releng/10.1/lib/libc/net/linkaddr.c 309696 2016-12-07 23:34:06Z glebius $");
3586618Sknu
3688084Sache#include <sys/types.h>
3788084Sache#include <sys/socket.h>
3896376Salfred#include <net/if.h>
3986618Sknu#include <net/if_dl.h>
4086618Sknu#include <string.h>
4186618Sknu
4286618Sknu/* States*/
4386618Sknu#define NAMING	0
4486618Sknu#define GOTONE	1
4586618Sknu#define GOTTWO	2
4686618Sknu#define RESET	3
4786618Sknu/* Inputs */
4886618Sknu#define	DIGIT	(4*0)
4986618Sknu#define	END	(4*1)
5086618Sknu#define DELIM	(4*2)
5149884Ssheldonh#define LETTER	(4*3)
5249884Ssheldonh
5349884Ssheldonhvoid
5449884Ssheldonhlink_addr(addr, sdl)
5549884Ssheldonh	const char *addr;
5649884Ssheldonh	struct sockaddr_dl *sdl;
5749884Ssheldonh{
5849884Ssheldonh	char *cp = sdl->sdl_data;
5949884Ssheldonh	char *cplim = sdl->sdl_len + (char *)sdl;
6049884Ssheldonh	int byte = 0, state = NAMING, new;
6149884Ssheldonh
621556Srgrimes	bzero((char *)&sdl->sdl_family, sdl->sdl_len - 1);
6349884Ssheldonh	sdl->sdl_family = AF_LINK;
6449884Ssheldonh	do {
6549884Ssheldonh		state &= ~LETTER;
6649884Ssheldonh		if ((*addr >= '0') && (*addr <= '9')) {
671556Srgrimes			new = *addr - '0';
6849884Ssheldonh		} else if ((*addr >= 'a') && (*addr <= 'f')) {
6949884Ssheldonh			new = *addr - 'a' + 10;
7049884Ssheldonh		} else if ((*addr >= 'A') && (*addr <= 'F')) {
7149884Ssheldonh			new = *addr - 'A' + 10;
7249884Ssheldonh		} else if (*addr == 0) {
7349884Ssheldonh			state |= END;
7449884Ssheldonh		} else if (state == NAMING &&
7549884Ssheldonh			   (((*addr >= 'A') && (*addr <= 'Z')) ||
7649884Ssheldonh			   ((*addr >= 'a') && (*addr <= 'z'))))
7749884Ssheldonh			state |= LETTER;
7849884Ssheldonh		else
7949884Ssheldonh			state |= DELIM;
8049884Ssheldonh		addr++;
8149884Ssheldonh		switch (state /* | INPUT */) {
8249884Ssheldonh		case NAMING | DIGIT:
8349884Ssheldonh		case NAMING | LETTER:
8449884Ssheldonh			*cp++ = addr[-1];
8549884Ssheldonh			continue;
8649884Ssheldonh		case NAMING | DELIM:
8749884Ssheldonh			state = RESET;
8849884Ssheldonh			sdl->sdl_nlen = cp - sdl->sdl_data;
8949884Ssheldonh			continue;
9049884Ssheldonh		case GOTTWO | DIGIT:
9149884Ssheldonh			*cp++ = byte;
9249884Ssheldonh			/* FALLTHROUGH */
9349884Ssheldonh		case RESET | DIGIT:
9449884Ssheldonh			state = GOTONE;
9549884Ssheldonh			byte = new;
9649884Ssheldonh			continue;
9749884Ssheldonh		case GOTONE | DIGIT:
9849884Ssheldonh			state = GOTTWO;
9949884Ssheldonh			byte = new + (byte << 4);
10049884Ssheldonh			continue;
10149884Ssheldonh		default: /* | DELIM */
10249884Ssheldonh			state = RESET;
10349884Ssheldonh			*cp++ = byte;
10449884Ssheldonh			byte = 0;
10549884Ssheldonh			continue;
10649884Ssheldonh		case GOTONE | END:
10749884Ssheldonh		case GOTTWO | END:
10849884Ssheldonh			*cp++ = byte;
1091556Srgrimes			/* FALLTHROUGH */
1101556Srgrimes		case RESET | END:
11149884Ssheldonh			break;
11249884Ssheldonh		}
11349884Ssheldonh		break;
11449884Ssheldonh	} while (cp < cplim);
11549884Ssheldonh	sdl->sdl_alen = cp - LLADDR(sdl);
11649884Ssheldonh	new = cp - (char *)sdl;
1171556Srgrimes	if (new > sizeof(*sdl))
1181556Srgrimes		sdl->sdl_len = new;
11949884Ssheldonh	return;
12049884Ssheldonh}
12149884Ssheldonh
12249884Ssheldonhstatic const char hexlist[] = "0123456789abcdef";
12349884Ssheldonh
12449884Ssheldonhchar *
12549884Ssheldonhlink_ntoa(sdl)
12649884Ssheldonh	const struct sockaddr_dl *sdl;
12749884Ssheldonh{
12849884Ssheldonh	static char obuf[64];
12949884Ssheldonh	_Static_assert(sizeof(obuf) >= IFNAMSIZ + 20, "obuf is too small");
13049884Ssheldonh	char *out;
13149884Ssheldonh	const u_char *in, *inlim;
13249884Ssheldonh	int namelen, i, rem;
13349884Ssheldonh
13449884Ssheldonh	namelen = (sdl->sdl_nlen <= IFNAMSIZ) ? sdl->sdl_nlen : IFNAMSIZ;
13549884Ssheldonh
13649884Ssheldonh	out = obuf;
13749884Ssheldonh	rem = sizeof(obuf);
13849884Ssheldonh	if (namelen > 0) {
13949884Ssheldonh		bcopy(sdl->sdl_data, out, namelen);
14049884Ssheldonh		out += namelen;
14149884Ssheldonh		rem -= namelen;
14249884Ssheldonh		if (sdl->sdl_alen > 0) {
14349884Ssheldonh			*out++ = ':';
14449884Ssheldonh			rem--;
14549884Ssheldonh		}
14649884Ssheldonh	}
14749884Ssheldonh
14849884Ssheldonh	in = (const u_char *)sdl->sdl_data + sdl->sdl_nlen;
14949884Ssheldonh	inlim = in + sdl->sdl_alen;
15049884Ssheldonh
15149884Ssheldonh	while (in < inlim && rem > 1) {
15249884Ssheldonh		if (in != (const u_char *)sdl->sdl_data + sdl->sdl_nlen) {
15349884Ssheldonh			*out++ = '.';
15449884Ssheldonh			rem--;
15549884Ssheldonh		}
15649884Ssheldonh		i = *in++;
15749884Ssheldonh		if (i > 0xf) {
15849884Ssheldonh			if (rem < 3)
15949884Ssheldonh				break;
16049884Ssheldonh			*out++ = hexlist[i >> 4];
16149884Ssheldonh			*out++ = hexlist[i & 0xf];
16249884Ssheldonh			rem -= 2;
1631556Srgrimes		} else {
1641556Srgrimes			if (rem < 2)
16549884Ssheldonh				break;
16649884Ssheldonh			*out++ = hexlist[i];
1671556Srgrimes			rem--;
16890111Simp		}
16990111Simp	}
17090111Simp	*out = 0;
17190111Simp	return (obuf);
17290111Simp}
17393345Sache