11573Srgrimes/*-
21573Srgrimes * Copyright (c) 1990, 1993
31573Srgrimes *	The Regents of the University of California.  All rights reserved.
41573Srgrimes *
51573Srgrimes * Redistribution and use in source and binary forms, with or without
61573Srgrimes * modification, are permitted provided that the following conditions
71573Srgrimes * are met:
81573Srgrimes * 1. Redistributions of source code must retain the above copyright
91573Srgrimes *    notice, this list of conditions and the following disclaimer.
101573Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111573Srgrimes *    notice, this list of conditions and the following disclaimer in the
121573Srgrimes *    documentation and/or other materials provided with the distribution.
131573Srgrimes * 4. Neither the name of the University nor the names of its contributors
141573Srgrimes *    may be used to endorse or promote products derived from this software
151573Srgrimes *    without specific prior written permission.
161573Srgrimes *
171573Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
181573Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
191573Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
201573Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
211573Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
221573Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
231573Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
241573Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
251573Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
261573Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
271573Srgrimes * SUCH DAMAGE.
281573Srgrimes */
291573Srgrimes
301573Srgrimes#if defined(LIBC_SCCS) && !defined(lint)
311573Srgrimesstatic char sccsid[] = "@(#)linkaddr.c	8.1 (Berkeley) 6/4/93";
321573Srgrimes#endif /* LIBC_SCCS and not lint */
3392889Sobrien#include <sys/cdefs.h>
3492889Sobrien__FBSDID("$FreeBSD: releng/9.3/lib/libc/net/linkaddr.c 309697 2016-12-07 23:35:15Z glebius $");
351573Srgrimes
361573Srgrimes#include <sys/types.h>
371573Srgrimes#include <sys/socket.h>
38309637Sglebius#include <net/if.h>
391573Srgrimes#include <net/if_dl.h>
401573Srgrimes#include <string.h>
411573Srgrimes
421573Srgrimes/* States*/
431573Srgrimes#define NAMING	0
441573Srgrimes#define GOTONE	1
451573Srgrimes#define GOTTWO	2
461573Srgrimes#define RESET	3
471573Srgrimes/* Inputs */
481573Srgrimes#define	DIGIT	(4*0)
491573Srgrimes#define	END	(4*1)
501573Srgrimes#define DELIM	(4*2)
511573Srgrimes#define LETTER	(4*3)
521573Srgrimes
531573Srgrimesvoid
541573Srgrimeslink_addr(addr, sdl)
5592889Sobrien	const char *addr;
5692889Sobrien	struct sockaddr_dl *sdl;
571573Srgrimes{
5892889Sobrien	char *cp = sdl->sdl_data;
591573Srgrimes	char *cplim = sdl->sdl_len + (char *)sdl;
6092889Sobrien	int byte = 0, state = NAMING, new;
611573Srgrimes
621573Srgrimes	bzero((char *)&sdl->sdl_family, sdl->sdl_len - 1);
631573Srgrimes	sdl->sdl_family = AF_LINK;
641573Srgrimes	do {
651573Srgrimes		state &= ~LETTER;
661573Srgrimes		if ((*addr >= '0') && (*addr <= '9')) {
671573Srgrimes			new = *addr - '0';
681573Srgrimes		} else if ((*addr >= 'a') && (*addr <= 'f')) {
691573Srgrimes			new = *addr - 'a' + 10;
701573Srgrimes		} else if ((*addr >= 'A') && (*addr <= 'F')) {
711573Srgrimes			new = *addr - 'A' + 10;
721573Srgrimes		} else if (*addr == 0) {
731573Srgrimes			state |= END;
741573Srgrimes		} else if (state == NAMING &&
751573Srgrimes			   (((*addr >= 'A') && (*addr <= 'Z')) ||
761573Srgrimes			   ((*addr >= 'a') && (*addr <= 'z'))))
771573Srgrimes			state |= LETTER;
781573Srgrimes		else
791573Srgrimes			state |= DELIM;
801573Srgrimes		addr++;
811573Srgrimes		switch (state /* | INPUT */) {
821573Srgrimes		case NAMING | DIGIT:
831573Srgrimes		case NAMING | LETTER:
841573Srgrimes			*cp++ = addr[-1];
851573Srgrimes			continue;
861573Srgrimes		case NAMING | DELIM:
871573Srgrimes			state = RESET;
881573Srgrimes			sdl->sdl_nlen = cp - sdl->sdl_data;
891573Srgrimes			continue;
901573Srgrimes		case GOTTWO | DIGIT:
911573Srgrimes			*cp++ = byte;
921573Srgrimes			/* FALLTHROUGH */
931573Srgrimes		case RESET | DIGIT:
941573Srgrimes			state = GOTONE;
951573Srgrimes			byte = new;
961573Srgrimes			continue;
971573Srgrimes		case GOTONE | DIGIT:
981573Srgrimes			state = GOTTWO;
991573Srgrimes			byte = new + (byte << 4);
1001573Srgrimes			continue;
1011573Srgrimes		default: /* | DELIM */
1021573Srgrimes			state = RESET;
1031573Srgrimes			*cp++ = byte;
1041573Srgrimes			byte = 0;
1051573Srgrimes			continue;
1061573Srgrimes		case GOTONE | END:
1071573Srgrimes		case GOTTWO | END:
1081573Srgrimes			*cp++ = byte;
1091573Srgrimes			/* FALLTHROUGH */
1101573Srgrimes		case RESET | END:
1111573Srgrimes			break;
1121573Srgrimes		}
1131573Srgrimes		break;
1148870Srgrimes	} while (cp < cplim);
1151573Srgrimes	sdl->sdl_alen = cp - LLADDR(sdl);
1161573Srgrimes	new = cp - (char *)sdl;
1171573Srgrimes	if (new > sizeof(*sdl))
1181573Srgrimes		sdl->sdl_len = new;
1191573Srgrimes	return;
1201573Srgrimes}
1211573Srgrimes
1221573Srgrimesstatic char hexlist[] = "0123456789abcdef";
1231573Srgrimes
1241573Srgrimeschar *
1251573Srgrimeslink_ntoa(sdl)
12692889Sobrien	const struct sockaddr_dl *sdl;
1271573Srgrimes{
1281573Srgrimes	static char obuf[64];
129309637Sglebius	_Static_assert(sizeof(obuf) >= IFNAMSIZ + 20, "obuf is too small");
130309637Sglebius	char *out;
131309697Sglebius	const u_char *in, *inlim;
132309637Sglebius	int namelen, i, rem;
1331573Srgrimes
134309637Sglebius	namelen = (sdl->sdl_nlen <= IFNAMSIZ) ? sdl->sdl_nlen : IFNAMSIZ;
135309637Sglebius
136309637Sglebius	out = obuf;
137309637Sglebius	rem = sizeof(obuf);
138309637Sglebius	if (namelen > 0) {
139309637Sglebius		bcopy(sdl->sdl_data, out, namelen);
140309637Sglebius		out += namelen;
141309637Sglebius		rem -= namelen;
142309637Sglebius		if (sdl->sdl_alen > 0) {
1431573Srgrimes			*out++ = ':';
144309637Sglebius			rem--;
145309637Sglebius		}
1461573Srgrimes	}
147309637Sglebius
148309697Sglebius	in = (const u_char *)sdl->sdl_data + sdl->sdl_nlen;
149309637Sglebius	inlim = in + sdl->sdl_alen;
150309637Sglebius
151309637Sglebius	while (in < inlim && rem > 1) {
152309697Sglebius		if (in != (const u_char *)sdl->sdl_data + sdl->sdl_nlen) {
1531573Srgrimes			*out++ = '.';
154309637Sglebius			rem--;
155309637Sglebius		}
1561573Srgrimes		i = *in++;
1571573Srgrimes		if (i > 0xf) {
158309637Sglebius			if (rem < 3)
159309637Sglebius				break;
160309697Sglebius			*out++ = hexlist[i >> 4];
161309637Sglebius			*out++ = hexlist[i & 0xf];
162309637Sglebius			rem -= 2;
163309637Sglebius		} else {
164309637Sglebius			if (rem < 2)
165309637Sglebius				break;
166309637Sglebius			*out++ = hexlist[i];
167309697Sglebius			rem--;
168309637Sglebius		}
1691573Srgrimes	}
1701573Srgrimes	*out = 0;
1711573Srgrimes	return (obuf);
1721573Srgrimes}
173