1872b698pfg/*-
2872b698pfg * SPDX-License-Identifier: BSD-3-Clause
3872b698pfg *
468cd876sam * Copyright (c) 1983, 1993
568cd876sam *	The Regents of the University of California.  All rights reserved.
668cd876sam *
768cd876sam * Redistribution and use in source and binary forms, with or without
868cd876sam * modification, are permitted provided that the following conditions
968cd876sam * are met:
1068cd876sam * 1. Redistributions of source code must retain the above copyright
1168cd876sam *    notice, this list of conditions and the following disclaimer.
1268cd876sam * 2. Redistributions in binary form must reproduce the above copyright
1368cd876sam *    notice, this list of conditions and the following disclaimer in the
1468cd876sam *    documentation and/or other materials provided with the distribution.
157e6cabdimp * 3. Neither the name of the University nor the names of its contributors
1668cd876sam *    may be used to endorse or promote products derived from this software
1768cd876sam *    without specific prior written permission.
1868cd876sam *
1968cd876sam * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2068cd876sam * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2168cd876sam * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2268cd876sam * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2368cd876sam * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2468cd876sam * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2568cd876sam * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2668cd876sam * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2768cd876sam * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2868cd876sam * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2968cd876sam * SUCH DAMAGE.
3068cd876sam */
3168cd876sam
3268cd876sam#ifndef lint
3368cd876samstatic const char rcsid[] =
3468cd876sam  "$FreeBSD$";
3568cd876sam#endif /* not lint */
3668cd876sam
3768cd876sam#include <sys/types.h>
3868cd876sam#include <sys/ioctl.h>
3968cd876sam#include <sys/socket.h>
4068cd876sam#include <net/if.h>
4168cd876sam
4268cd876sam#include <err.h>
4368cd876sam#include <stdio.h>
4468cd876sam#include <stdlib.h>
4568cd876sam#include <string.h>
46cd822ecsam#include <ifaddrs.h>
470cfdb3crpokala#include <unistd.h>
4868cd876sam
4968cd876sam#include <net/if_dl.h>
5068cd876sam#include <net/if_types.h>
5168cd876sam#include <net/ethernet.h>
5268cd876sam
5368cd876sam#include "ifconfig.h"
5468cd876sam
5568cd876samstatic struct ifreq link_ridreq;
5668cd876sam
57700d268allanjudeextern char *f_ether;
58700d268allanjude
5968cd876samstatic void
60cd822ecsamlink_status(int s __unused, const struct ifaddrs *ifa)
6168cd876sam{
62cd822ecsam	/* XXX no const 'cuz LLADDR is defined wrong */
639de2156kib	struct sockaddr_dl *sdl;
648e48e06allanjude	char *ether_format, *format_char;
659de2156kib	struct ifreq ifr;
669de2156kib	int n, rc, sock_hw;
679de2156kib	static const u_char laggaddr[6] = {0};
6868cd876sam
699de2156kib	sdl = (struct sockaddr_dl *) ifa->ifa_addr;
709de2156kib	if (sdl == NULL || sdl->sdl_alen == 0)
719de2156kib		return;
729de2156kib
739de2156kib	if ((sdl->sdl_type == IFT_ETHER || sdl->sdl_type == IFT_L2VLAN ||
749de2156kib	    sdl->sdl_type == IFT_BRIDGE) && sdl->sdl_alen == ETHER_ADDR_LEN) {
759de2156kib		ether_format = ether_ntoa((struct ether_addr *)LLADDR(sdl));
769de2156kib		if (f_ether != NULL && strcmp(f_ether, "dash") == 0) {
77525ed72allanjude			while ((format_char = strchr(ether_format, ':')) !=
78525ed72allanjude			    NULL) {
799de2156kib				*format_char = '-';
80525ed72allanjude			}
810cfdb3crpokala		}
829de2156kib		printf("\tether %s\n", ether_format);
839de2156kib	} else {
849de2156kib		n = sdl->sdl_nlen > 0 ? sdl->sdl_nlen + 1 : 0;
859de2156kib		printf("\tlladdr %s\n", link_ntoa(sdl) + n);
869de2156kib	}
879de2156kib
889de2156kib	/*
899de2156kib	 * Best-effort (i.e. failures are silent) to get original
909de2156kib	 * hardware address, as read by NIC driver at attach time. Only
919de2156kib	 * applies to Ethernet NICs (IFT_ETHER). However, laggX
929de2156kib	 * interfaces claim to be IFT_ETHER, and re-type their component
939de2156kib	 * Ethernet NICs as IFT_IEEE8023ADLAG. So, check for both. If
949de2156kib	 * the MAC is zeroed, then it's actually a lagg.
959de2156kib	 */
969de2156kib	if ((sdl->sdl_type != IFT_ETHER &&
979de2156kib	    sdl->sdl_type != IFT_IEEE8023ADLAG) ||
989de2156kib	    sdl->sdl_alen != ETHER_ADDR_LEN)
999de2156kib		return;
1009de2156kib
1019de2156kib	strncpy(ifr.ifr_name, ifa->ifa_name, sizeof(ifr.ifr_name));
1029de2156kib	memcpy(&ifr.ifr_addr, ifa->ifa_addr, sizeof(ifa->ifa_addr->sa_len));
1039de2156kib	ifr.ifr_addr.sa_family = AF_LOCAL;
1049de2156kib	if ((sock_hw = socket(AF_LOCAL, SOCK_DGRAM, 0)) < 0) {
1059de2156kib		warn("socket(AF_LOCAL,SOCK_DGRAM)");
1069de2156kib		return;
10768cd876sam	}
1089de2156kib	rc = ioctl(sock_hw, SIOCGHWADDR, &ifr);
1099de2156kib	close(sock_hw);
1109de2156kib	if (rc != 0)
1119de2156kib		return;
1129de2156kib
1139de2156kib	/*
1149de2156kib	 * If this is definitely a lagg device or the hwaddr
1159de2156kib	 * matches the link addr, don't bother.
1169de2156kib	 */
1179de2156kib	if (memcmp(ifr.ifr_addr.sa_data, laggaddr, sdl->sdl_alen) == 0 ||
1189de2156kib	    memcmp(ifr.ifr_addr.sa_data, LLADDR(sdl), sdl->sdl_alen) == 0)
1199de2156kib		goto pcp;
1209de2156kib
1219de2156kib	ether_format = ether_ntoa((const struct ether_addr *)
1229de2156kib	    &ifr.ifr_addr.sa_data);
1239de2156kib	if (f_ether != NULL && strcmp(f_ether, "dash") == 0) {
1249de2156kib		for (format_char = strchr(ether_format, ':');
1259de2156kib		     format_char != NULL;
1269de2156kib		     format_char = strchr(ether_format, ':'))
1279de2156kib			*format_char = '-';
1289de2156kib	}
1299de2156kib	printf("\thwaddr %s\n", ether_format);
1309de2156kib
1319de2156kibpcp:
1329de2156kib	if (ioctl(s, SIOCGLANPCP, (caddr_t)&ifr) == 0 &&
1339de2156kib	    ifr.ifr_lan_pcp != IFNET_PCP_NONE)
1349de2156kib		printf("\tpcp %d\n", ifr.ifr_lan_pcp);
13568cd876sam}
13668cd876sam
13768cd876samstatic void
13868cd876samlink_getaddr(const char *addr, int which)
13968cd876sam{
14068cd876sam	char *temp;
14168cd876sam	struct sockaddr_dl sdl;
14268cd876sam	struct sockaddr *sa = &link_ridreq.ifr_addr;
14368cd876sam
14468cd876sam	if (which != ADDR)
14568cd876sam		errx(1, "can't set link-level netmask or broadcast");
146df5ed9faraujo	if (!strcmp(addr, "random")) {
147df5ed9faraujo		sdl.sdl_len = sizeof(sdl);
148df5ed9faraujo		sdl.sdl_alen = ETHER_ADDR_LEN;
149df5ed9faraujo		sdl.sdl_nlen = 0;
150df5ed9faraujo		sdl.sdl_family = AF_LINK;
151df5ed9faraujo		arc4random_buf(&sdl.sdl_data, ETHER_ADDR_LEN);
1523be19b2araujo		/* Non-multicast and claim it is locally administered. */
153df5ed9faraujo		sdl.sdl_data[0] &= 0xfc;
1543be19b2araujo		sdl.sdl_data[0] |= 0x02;
155df5ed9faraujo	} else {
156df5ed9faraujo		if ((temp = malloc(strlen(addr) + 2)) == NULL)
157df5ed9faraujo			errx(1, "malloc failed");
158df5ed9faraujo		temp[0] = ':';
159df5ed9faraujo		strcpy(temp + 1, addr);
160df5ed9faraujo		sdl.sdl_len = sizeof(sdl);
161df5ed9faraujo		link_addr(temp, &sdl);
162df5ed9faraujo		free(temp);
163df5ed9faraujo	}
16468cd876sam	if (sdl.sdl_alen > sizeof(sa->sa_data))
16568cd876sam		errx(1, "malformed link-level address");
16668cd876sam	sa->sa_family = AF_LINK;
16768cd876sam	sa->sa_len = sdl.sdl_alen;
16868cd876sam	bcopy(LLADDR(&sdl), sa->sa_data, sdl.sdl_alen);
16968cd876sam}
17068cd876sam
17168cd876samstatic struct afswtch af_link = {
17268cd876sam	.af_name	= "link",
17368cd876sam	.af_af		= AF_LINK,
17468cd876sam	.af_status	= link_status,
17568cd876sam	.af_getaddr	= link_getaddr,
17668cd876sam	.af_aifaddr	= SIOCSIFLLADDR,
17768cd876sam	.af_addreq	= &link_ridreq,
17868cd876sam};
17968cd876samstatic struct afswtch af_ether = {
18068cd876sam	.af_name	= "ether",
18168cd876sam	.af_af		= AF_LINK,
18268cd876sam	.af_status	= link_status,
18368cd876sam	.af_getaddr	= link_getaddr,
18468cd876sam	.af_aifaddr	= SIOCSIFLLADDR,
18568cd876sam	.af_addreq	= &link_ridreq,
18668cd876sam};
18768cd876samstatic struct afswtch af_lladdr = {
18868cd876sam	.af_name	= "lladdr",
18968cd876sam	.af_af		= AF_LINK,
19068cd876sam	.af_status	= link_status,
19168cd876sam	.af_getaddr	= link_getaddr,
19268cd876sam	.af_aifaddr	= SIOCSIFLLADDR,
19368cd876sam	.af_addreq	= &link_ridreq,
19468cd876sam};
19568cd876sam
19668cd876samstatic __constructor void
19768cd876samlink_ctor(void)
19868cd876sam{
19968cd876sam	af_register(&af_link);
20068cd876sam	af_register(&af_ether);
20168cd876sam	af_register(&af_lladdr);
20268cd876sam}
203