xref: /freebsd/lib/libc/net/linkaddr.c (revision dc36d6f9bb1753f3808552f3afd30eda9a7b206a)
158f0484fSRodney W. Grimes /*-
2*8a16b7a1SPedro F. Giffuni  * SPDX-License-Identifier: BSD-3-Clause
3*8a16b7a1SPedro F. Giffuni  *
458f0484fSRodney W. Grimes  * Copyright (c) 1990, 1993
558f0484fSRodney W. Grimes  *	The Regents of the University of California.  All rights reserved.
658f0484fSRodney W. Grimes  *
758f0484fSRodney W. Grimes  * Redistribution and use in source and binary forms, with or without
858f0484fSRodney W. Grimes  * modification, are permitted provided that the following conditions
958f0484fSRodney W. Grimes  * are met:
1058f0484fSRodney W. Grimes  * 1. Redistributions of source code must retain the above copyright
1158f0484fSRodney W. Grimes  *    notice, this list of conditions and the following disclaimer.
1258f0484fSRodney W. Grimes  * 2. Redistributions in binary form must reproduce the above copyright
1358f0484fSRodney W. Grimes  *    notice, this list of conditions and the following disclaimer in the
1458f0484fSRodney W. Grimes  *    documentation and/or other materials provided with the distribution.
15fbbd9655SWarner Losh  * 3. Neither the name of the University nor the names of its contributors
1658f0484fSRodney W. Grimes  *    may be used to endorse or promote products derived from this software
1758f0484fSRodney W. Grimes  *    without specific prior written permission.
1858f0484fSRodney W. Grimes  *
1958f0484fSRodney W. Grimes  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2058f0484fSRodney W. Grimes  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2158f0484fSRodney W. Grimes  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2258f0484fSRodney W. Grimes  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2358f0484fSRodney W. Grimes  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2458f0484fSRodney W. Grimes  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2558f0484fSRodney W. Grimes  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2658f0484fSRodney W. Grimes  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2758f0484fSRodney W. Grimes  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2858f0484fSRodney W. Grimes  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2958f0484fSRodney W. Grimes  * SUCH DAMAGE.
3058f0484fSRodney W. Grimes  */
3158f0484fSRodney W. Grimes 
3258f0484fSRodney W. Grimes #include <sys/types.h>
3358f0484fSRodney W. Grimes #include <sys/socket.h>
3474e540d7SGleb Smirnoff #include <net/if.h>
3558f0484fSRodney W. Grimes #include <net/if_dl.h>
3658f0484fSRodney W. Grimes #include <string.h>
3758f0484fSRodney W. Grimes 
3858f0484fSRodney W. Grimes /* States*/
3958f0484fSRodney W. Grimes #define NAMING	0
4058f0484fSRodney W. Grimes #define GOTONE	1
4158f0484fSRodney W. Grimes #define GOTTWO	2
4258f0484fSRodney W. Grimes #define RESET	3
4358f0484fSRodney W. Grimes /* Inputs */
4458f0484fSRodney W. Grimes #define	DIGIT	(4*0)
4558f0484fSRodney W. Grimes #define	END	(4*1)
4658f0484fSRodney W. Grimes #define DELIM	(4*2)
4758f0484fSRodney W. Grimes #define LETTER	(4*3)
4858f0484fSRodney W. Grimes 
4958f0484fSRodney W. Grimes void
link_addr(const char * addr,struct sockaddr_dl * sdl)50626c9d74SCraig Rodrigues link_addr(const char *addr, struct sockaddr_dl *sdl)
5158f0484fSRodney W. Grimes {
528fb3f3f6SDavid E. O'Brien 	char *cp = sdl->sdl_data;
5358f0484fSRodney W. Grimes 	char *cplim = sdl->sdl_len + (char *)sdl;
548fb3f3f6SDavid E. O'Brien 	int byte = 0, state = NAMING, new;
5558f0484fSRodney W. Grimes 
5658f0484fSRodney W. Grimes 	bzero((char *)&sdl->sdl_family, sdl->sdl_len - 1);
5758f0484fSRodney W. Grimes 	sdl->sdl_family = AF_LINK;
5858f0484fSRodney W. Grimes 	do {
5958f0484fSRodney W. Grimes 		state &= ~LETTER;
6058f0484fSRodney W. Grimes 		if ((*addr >= '0') && (*addr <= '9')) {
6158f0484fSRodney W. Grimes 			new = *addr - '0';
6258f0484fSRodney W. Grimes 		} else if ((*addr >= 'a') && (*addr <= 'f')) {
6358f0484fSRodney W. Grimes 			new = *addr - 'a' + 10;
6458f0484fSRodney W. Grimes 		} else if ((*addr >= 'A') && (*addr <= 'F')) {
6558f0484fSRodney W. Grimes 			new = *addr - 'A' + 10;
6658f0484fSRodney W. Grimes 		} else if (*addr == 0) {
6758f0484fSRodney W. Grimes 			state |= END;
6858f0484fSRodney W. Grimes 		} else if (state == NAMING &&
6958f0484fSRodney W. Grimes 			   (((*addr >= 'A') && (*addr <= 'Z')) ||
7058f0484fSRodney W. Grimes 			   ((*addr >= 'a') && (*addr <= 'z'))))
7158f0484fSRodney W. Grimes 			state |= LETTER;
7258f0484fSRodney W. Grimes 		else
7358f0484fSRodney W. Grimes 			state |= DELIM;
7458f0484fSRodney W. Grimes 		addr++;
7558f0484fSRodney W. Grimes 		switch (state /* | INPUT */) {
7658f0484fSRodney W. Grimes 		case NAMING | DIGIT:
7758f0484fSRodney W. Grimes 		case NAMING | LETTER:
7858f0484fSRodney W. Grimes 			*cp++ = addr[-1];
7958f0484fSRodney W. Grimes 			continue;
8058f0484fSRodney W. Grimes 		case NAMING | DELIM:
8158f0484fSRodney W. Grimes 			state = RESET;
8258f0484fSRodney W. Grimes 			sdl->sdl_nlen = cp - sdl->sdl_data;
8358f0484fSRodney W. Grimes 			continue;
8458f0484fSRodney W. Grimes 		case GOTTWO | DIGIT:
8558f0484fSRodney W. Grimes 			*cp++ = byte;
8658f0484fSRodney W. Grimes 			/* FALLTHROUGH */
8758f0484fSRodney W. Grimes 		case RESET | DIGIT:
8858f0484fSRodney W. Grimes 			state = GOTONE;
8958f0484fSRodney W. Grimes 			byte = new;
9058f0484fSRodney W. Grimes 			continue;
9158f0484fSRodney W. Grimes 		case GOTONE | DIGIT:
9258f0484fSRodney W. Grimes 			state = GOTTWO;
9358f0484fSRodney W. Grimes 			byte = new + (byte << 4);
9458f0484fSRodney W. Grimes 			continue;
9558f0484fSRodney W. Grimes 		default: /* | DELIM */
9658f0484fSRodney W. Grimes 			state = RESET;
9758f0484fSRodney W. Grimes 			*cp++ = byte;
9858f0484fSRodney W. Grimes 			byte = 0;
9958f0484fSRodney W. Grimes 			continue;
10058f0484fSRodney W. Grimes 		case GOTONE | END:
10158f0484fSRodney W. Grimes 		case GOTTWO | END:
10258f0484fSRodney W. Grimes 			*cp++ = byte;
10358f0484fSRodney W. Grimes 			/* FALLTHROUGH */
10458f0484fSRodney W. Grimes 		case RESET | END:
10558f0484fSRodney W. Grimes 			break;
10658f0484fSRodney W. Grimes 		}
10758f0484fSRodney W. Grimes 		break;
10858f0484fSRodney W. Grimes 	} while (cp < cplim);
10958f0484fSRodney W. Grimes 	sdl->sdl_alen = cp - LLADDR(sdl);
11058f0484fSRodney W. Grimes 	new = cp - (char *)sdl;
11158f0484fSRodney W. Grimes 	if (new > sizeof(*sdl))
11258f0484fSRodney W. Grimes 		sdl->sdl_len = new;
11358f0484fSRodney W. Grimes 	return;
11458f0484fSRodney W. Grimes }
11558f0484fSRodney W. Grimes 
116905dd80fSPedro F. Giffuni static const char hexlist[] = "0123456789abcdef";
11758f0484fSRodney W. Grimes 
11858f0484fSRodney W. Grimes char *
link_ntoa(const struct sockaddr_dl * sdl)119626c9d74SCraig Rodrigues link_ntoa(const struct sockaddr_dl *sdl)
12058f0484fSRodney W. Grimes {
12158f0484fSRodney W. Grimes 	static char obuf[64];
12274e540d7SGleb Smirnoff 	_Static_assert(sizeof(obuf) >= IFNAMSIZ + 20, "obuf is too small");
12374e540d7SGleb Smirnoff 	char *out;
124faf19a69SGleb Smirnoff 	const u_char *in, *inlim;
12574e540d7SGleb Smirnoff 	int namelen, i, rem;
12658f0484fSRodney W. Grimes 
12774e540d7SGleb Smirnoff 	namelen = (sdl->sdl_nlen <= IFNAMSIZ) ? sdl->sdl_nlen : IFNAMSIZ;
12874e540d7SGleb Smirnoff 
12974e540d7SGleb Smirnoff 	out = obuf;
13074e540d7SGleb Smirnoff 	rem = sizeof(obuf);
13174e540d7SGleb Smirnoff 	if (namelen > 0) {
13274e540d7SGleb Smirnoff 		bcopy(sdl->sdl_data, out, namelen);
13374e540d7SGleb Smirnoff 		out += namelen;
13474e540d7SGleb Smirnoff 		rem -= namelen;
13574e540d7SGleb Smirnoff 		if (sdl->sdl_alen > 0) {
13658f0484fSRodney W. Grimes 			*out++ = ':';
13774e540d7SGleb Smirnoff 			rem--;
13858f0484fSRodney W. Grimes 		}
13974e540d7SGleb Smirnoff 	}
14074e540d7SGleb Smirnoff 
141faf19a69SGleb Smirnoff 	in = (const u_char *)sdl->sdl_data + sdl->sdl_nlen;
14274e540d7SGleb Smirnoff 	inlim = in + sdl->sdl_alen;
14374e540d7SGleb Smirnoff 
14474e540d7SGleb Smirnoff 	while (in < inlim && rem > 1) {
145faf19a69SGleb Smirnoff 		if (in != (const u_char *)sdl->sdl_data + sdl->sdl_nlen) {
14658f0484fSRodney W. Grimes 			*out++ = '.';
14774e540d7SGleb Smirnoff 			rem--;
14874e540d7SGleb Smirnoff 		}
14958f0484fSRodney W. Grimes 		i = *in++;
15058f0484fSRodney W. Grimes 		if (i > 0xf) {
15174e540d7SGleb Smirnoff 			if (rem < 3)
15274e540d7SGleb Smirnoff 				break;
153faf19a69SGleb Smirnoff 			*out++ = hexlist[i >> 4];
15474e540d7SGleb Smirnoff 			*out++ = hexlist[i & 0xf];
15574e540d7SGleb Smirnoff 			rem -= 2;
15674e540d7SGleb Smirnoff 		} else {
15774e540d7SGleb Smirnoff 			if (rem < 2)
15874e540d7SGleb Smirnoff 				break;
15974e540d7SGleb Smirnoff 			*out++ = hexlist[i];
160faf19a69SGleb Smirnoff 			rem--;
16174e540d7SGleb Smirnoff 		}
16258f0484fSRodney W. Grimes 	}
16358f0484fSRodney W. Grimes 	*out = 0;
16458f0484fSRodney W. Grimes 	return (obuf);
16558f0484fSRodney W. Grimes }
166