diff options
author | rpokala <rpokala@FreeBSD.org> | 2017-05-17 22:29:25 +0000 |
---|---|---|
committer | rpokala <rpokala@FreeBSD.org> | 2017-05-17 22:29:25 +0000 |
commit | 2ce46e31d62424593e08c3853efe8c1e9283aba2 (patch) | |
tree | b2d309a8e52a1ac150a4313fc6caf15b78014f9a | |
parent | 41d2a3bce7ead4e7867724598cfae85b83ec0d21 (diff) | |
download | FreeBSD-src-2ce46e31d62424593e08c3853efe8c1e9283aba2.zip FreeBSD-src-2ce46e31d62424593e08c3853efe8c1e9283aba2.tar.gz |
MFC r318160, 318176: Persistently store NIC's hardware MAC address, and add
a way to retrive it
NOTE: Due to restructuring, the merges didn't apply cleanly; the resulting
change is almost identical to what went into stable/11, but in some cases in
different locations.
The MAC address reported by `ifconfig ${nic} ether' does not always match
the address in the hardware, as reported by the driver during attach. In
particular, NICs which are components of a lagg(4) interface all report the
same MAC.
When attaching, the NIC driver passes the MAC address it read from the
hardware as an argument to ether_ifattach(). Keep a second copy of it, and
create ioctl(SIOCGHWADDR) to return it. Teach `ifconfig' to report it along
with the active MAC address.
PR: 194386
-rw-r--r-- | sbin/ifconfig/af_link.c | 36 | ||||
-rw-r--r-- | sys/net/if.c | 34 | ||||
-rw-r--r-- | sys/net/if_ethersubr.c | 3 | ||||
-rw-r--r-- | sys/net/if_var.h | 2 | ||||
-rw-r--r-- | sys/sys/sockio.h | 1 |
5 files changed, 76 insertions, 0 deletions
diff --git a/sbin/ifconfig/af_link.c b/sbin/ifconfig/af_link.c index 4a4b661..d3e8896 100644 --- a/sbin/ifconfig/af_link.c +++ b/sbin/ifconfig/af_link.c @@ -42,6 +42,7 @@ static const char rcsid[] = #include <stdlib.h> #include <string.h> #include <ifaddrs.h> +#include <unistd.h> #include <net/if_dl.h> #include <net/if_types.h> @@ -69,6 +70,41 @@ link_status(int s __unused, const struct ifaddrs *ifa) printf("\tlladdr %s\n", link_ntoa(sdl) + n); } + /* Best-effort (i.e. failures are silent) to get original + * hardware address, as read by NIC driver at attach time. Only + * applies to Ethernet NICs (IFT_ETHER). However, laggX + * interfaces claim to be IFT_ETHER, and re-type their component + * Ethernet NICs as IFT_IEEE8023ADLAG. So, check for both. If + * the MAC is zeroed, then it's actually a lagg. + */ + if ((sdl->sdl_type == IFT_ETHER || + sdl->sdl_type == IFT_IEEE8023ADLAG) && + sdl->sdl_alen == ETHER_ADDR_LEN) { + struct ifreq ifr; + int sock_hw; + int rc; + static const u_char laggaddr[6] = {0}; + + 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 ((sock_hw = socket(AF_LOCAL, SOCK_DGRAM, 0)) < 0) { + warn("socket(AF_LOCAL,SOCK_DGRAM)"); + return; + } + rc = ioctl(sock_hw, SIOCGHWADDR, &ifr); + close(sock_hw); + if (rc != 0) { + return; + } + if (memcmp(ifr.ifr_addr.sa_data, laggaddr, sdl->sdl_alen) == 0) { + return; + } + printf("\thwaddr %s\n", ether_ntoa((const struct ether_addr *) + &ifr.ifr_addr.sa_data)); + } } } diff --git a/sys/net/if.c b/sys/net/if.c index 625b6d0..e403e8c 100644 --- a/sys/net/if.c +++ b/sys/net/if.c @@ -732,6 +732,11 @@ if_attach_internal(struct ifnet *ifp, int vmove, struct if_clone *ifc) /* Reliably crash if used uninitialized. */ ifp->if_broadcastaddr = NULL; + if (ifp->if_type == IFT_ETHER) { + ifp->if_hw_addr = malloc(ifp->if_addrlen, M_IFADDR, + M_WAITOK | M_ZERO); + } + #if defined(INET) || defined(INET6) /* Use defaults for TSO, if nothing is set */ if (ifp->if_hw_tsomax == 0 && @@ -988,6 +993,8 @@ if_detach_internal(struct ifnet *ifp, int vmove, struct if_clone **ifcp) * Remove link ifaddr pointer and maybe decrement if_index. * Clean up all addresses. */ + free(ifp->if_hw_addr, M_IFADDR); + ifp->if_hw_addr = NULL; ifp->if_addr = NULL; /* We can now free link ifaddr. */ @@ -2639,6 +2646,10 @@ ifhwioctl(u_long cmd, struct ifnet *ifp, caddr_t data, struct thread *td) EVENTHANDLER_INVOKE(iflladdr_event, ifp); break; + case SIOCGHWADDR: + error = if_gethwaddr(ifp, ifr); + break; + case SIOCAIFGROUP: { struct ifgroupreq *ifgr = (struct ifgroupreq *)ifr; @@ -3578,6 +3589,29 @@ if_setlladdr(struct ifnet *ifp, const u_char *lladdr, int len) } /* + * Get the link layer address that was read from the hardware at attach. + * + * This is only set by Ethernet NICs (IFT_ETHER), but laggX interfaces re-type + * their component interfaces as IFT_IEEE8023ADLAG. + */ +int +if_gethwaddr(struct ifnet *ifp, struct ifreq *ifr) +{ + + if (ifp->if_hw_addr == NULL) + return (ENODEV); + + switch (ifp->if_type) { + case IFT_ETHER: + case IFT_IEEE8023ADLAG: + bcopy(ifp->if_hw_addr, ifr->ifr_addr.sa_data, ifp->if_addrlen); + return (0); + default: + return (ENODEV); + } +} + +/* * 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 diff --git a/sys/net/if_ethersubr.c b/sys/net/if_ethersubr.c index ea22d33..9e843f1 100644 --- a/sys/net/if_ethersubr.c +++ b/sys/net/if_ethersubr.c @@ -918,6 +918,9 @@ ether_ifattach(struct ifnet *ifp, const u_int8_t *lla) sdl->sdl_alen = ifp->if_addrlen; bcopy(lla, LLADDR(sdl), ifp->if_addrlen); + if (ifp->if_hw_addr != NULL) + bcopy(lla, ifp->if_hw_addr, ifp->if_addrlen); + bpfattach(ifp, DLT_EN10MB, ETHER_HDR_LEN); if (ng_ether_attach_p != NULL) (*ng_ether_attach_p)(ifp); diff --git a/sys/net/if_var.h b/sys/net/if_var.h index 1456793..94f0247 100644 --- a/sys/net/if_var.h +++ b/sys/net/if_var.h @@ -200,6 +200,7 @@ struct ifnet { (struct ifnet *, struct vnet *, char *); struct vnet *if_home_vnet; /* where this ifnet originates from */ struct ifaddr *if_addr; /* pointer to link-level address */ + void *if_hw_addr; /* hardware link-level address */ void *if_llsoftc; /* link layer softc */ int if_drv_flags; /* driver-managed status flags */ struct ifaltq if_snd; /* output queue (includes altq) */ @@ -973,6 +974,7 @@ void if_qflush(struct ifnet *); void if_ref(struct ifnet *); void if_rele(struct ifnet *); int if_setlladdr(struct ifnet *, const u_char *, int); +int if_gethwaddr(struct ifnet *, struct ifreq *); void if_up(struct ifnet *); int ifioctl(struct socket *, u_long, caddr_t, struct thread *); int ifpromisc(struct ifnet *, int); diff --git a/sys/sys/sockio.h b/sys/sys/sockio.h index f942942..0dfce53 100644 --- a/sys/sys/sockio.h +++ b/sys/sys/sockio.h @@ -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 ifreq) /* get I2C data */ +#define SIOCGHWADDR _IOWR('i', 62, struct ifreq) /* get hardware lladdr */ #define SIOCSIFPHYADDR _IOW('i', 70, struct ifaliasreq) /* set gif address */ #define SIOCGIFPSRCADDR _IOWR('i', 71, struct ifreq) /* get gif psrc addr */ |