--- sbin/ifconfig/af_link.c (revision 273146) +++ sbin/ifconfig/af_link.c (working copy) @@ -42,6 +42,7 @@ #include #include #include +#include #include #include @@ -61,9 +62,30 @@ if ((sdl->sdl_type == IFT_ETHER || sdl->sdl_type == IFT_L2VLAN || sdl->sdl_type == IFT_BRIDGE) && - sdl->sdl_alen == ETHER_ADDR_LEN) + sdl->sdl_alen == ETHER_ADDR_LEN) { + struct ifreq ifr; + int s_hw; printf("\tether %s\n", ether_ntoa((struct ether_addr *)LLADDR(sdl))); + strncpy(ifr.ifr_name, ifa->ifa_name, + sizeof(ifr.ifr_name)); + memcpy(&ifr.ifr_addr, ifa->ifa_addr, + sizeof(ifa->ifa_addr->sa_len)); + ifr.ifr_addr.sa_family = AF_LOCAL; + if ((s_hw = socket(AF_LOCAL, SOCK_DGRAM, 0)) < 0) { + warn("socket(AF_LOCAL,SOCK_DGRAM)"); + return; + } + if (ioctl(s_hw, SIOCGHWLLADDR, &ifr) < 0) { + warn("SIOCGHWLLADDR"); + close(s_hw); + return; + } + printf("\thwaddr %s\n", + ether_ntoa((const struct ether_addr *) + &ifr.ifr_addr.sa_data)); + close(s_hw); + } else { int n = sdl->sdl_nlen > 0 ? sdl->sdl_nlen + 1 : 0; --- sys/net/if.c (revision 273146) +++ sys/net/if.c (working copy) @@ -2613,6 +2613,10 @@ EVENTHANDLER_INVOKE(iflladdr_event, ifp); break; + case SIOCGHWLLADDR: + error = if_gethwlladdr(ifp, ifr); + break; + case SIOCAIFGROUP: { struct ifgroupreq *ifgr = (struct ifgroupreq *)ifr; @@ -3486,6 +3490,33 @@ } /* + * Get the link layer address that was read from the hardware at probe. + * + * At this time we only support certain types of interfaces. + */ +int +if_gethwlladdr(struct ifnet *ifp, struct ifreq *ifr) +{ + switch (ifp->if_type) { + case IFT_ETHER: + case IFT_FDDI: + case IFT_XETHER: + case IFT_ISO88025: + case IFT_L2VLAN: + case IFT_BRIDGE: + case IFT_ARCNET: + case IFT_IEEE8023ADLAG: + case IFT_IEEE80211: + bcopy(&IFP2AC(ifp)->hw_lladdr, ifr->ifr_addr.sa_data, ETHER_ADDR_LEN); + ifr->ifr_addr.sa_len = ETHER_ADDR_LEN; + break; + default: + return (ENODEV); + } + return (0); +} + +/* * The name argument must be a pointer to storage which will last as * long as the interface does. For physical devices, the result of * device_get_name(dev) is a good choice and for pseudo-devices a --- sys/net/if_arp.h (revision 273146) +++ sys/net/if_arp.h (working copy) @@ -102,9 +102,11 @@ * Structure shared between the ethernet driver modules and * the address resolution code. */ +#include struct arpcom { struct ifnet *ac_ifp; /* network-visible interface */ void *ac_netgraph; /* ng_ether(4) netgraph node info */ + struct ether_addr hw_lladdr; /* original lladdr from hardware */ }; #define IFP2AC(ifp) ((struct arpcom *)(ifp->if_l2com)) #define AC2IFP(ac) ((ac)->ac_ifp) --- sys/net/if_ethersubr.c (revision 273146) +++ sys/net/if_ethersubr.c (working copy) @@ -841,6 +841,7 @@ sdl->sdl_type = IFT_ETHER; sdl->sdl_alen = ifp->if_addrlen; bcopy(lla, LLADDR(sdl), ifp->if_addrlen); + bcopy(lla, &IFP2AC(ifp)->hw_lladdr, ifp->if_addrlen); bpfattach(ifp, DLT_EN10MB, ETHER_HDR_LEN); if (ng_ether_attach_p != NULL) --- sys/net/if_var.h (revision 273146) +++ sys/net/if_var.h (working copy) @@ -498,6 +498,7 @@ void if_ref(struct ifnet *); void if_rele(struct ifnet *); int if_setlladdr(struct ifnet *, const u_char *, int); +int if_gethwlladdr(struct ifnet *, struct ifreq *); void if_up(struct ifnet *); int ifioctl(struct socket *, u_long, caddr_t, struct thread *); int ifpromisc(struct ifnet *, int); --- sys/sys/sockio.h (revision 273146) +++ sys/sys/sockio.h (working copy) @@ -97,6 +97,7 @@ #define SIOCGIFSTATUS _IOWR('i', 59, struct ifstat) /* get IF status */ #define SIOCSIFLLADDR _IOW('i', 60, struct ifreq) /* set linklevel addr */ #define SIOCGI2C _IOWR('i', 61, struct ifstat) /* get I2C data */ +#define SIOCGHWLLADDR _IOWR('i', 62, struct ifreq) /* get hw lladdr */ #define SIOCSIFPHYADDR _IOW('i', 70, struct ifaliasreq) /* set gif addres */ #define SIOCGIFPSRCADDR _IOWR('i', 71, struct ifreq) /* get gif psrc addr */