diff options
author | rpokala <rpokala@FreeBSD.org> | 2017-05-17 05:53:25 +0000 |
---|---|---|
committer | rpokala <rpokala@FreeBSD.org> | 2017-05-17 05:53:25 +0000 |
commit | 2ff8b729046a2184760861e257c713eb6f329fa2 (patch) | |
tree | 0a51aa3b742113b43e0674d06ffaa8e1013e8720 | |
parent | 7b8496db357e6b89ee6083a3e16841eada7d2c26 (diff) | |
download | FreeBSD-src-2ff8b729046a2184760861e257c713eb6f329fa2.zip FreeBSD-src-2ff8b729046a2184760861e257c713eb6f329fa2.tar.gz |
MFC r318160, 318176: Persistently store NIC's hardware MAC address, and add
a way to retrive it
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 | 45 | ||||
-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, 84 insertions, 1 deletions
diff --git a/sbin/ifconfig/af_link.c b/sbin/ifconfig/af_link.c index c96cbd2..c2aafa7 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> @@ -67,7 +68,7 @@ link_status(int s __unused, const struct ifaddrs *ifa) sdl->sdl_alen == ETHER_ADDR_LEN) { ether_format = ether_ntoa((struct ether_addr *)LLADDR(sdl)); if (f_ether != NULL && strcmp(f_ether, "dash") == 0) { - for (format_char = strchr(ether_format, ':'); + for (format_char = strchr(ether_format, ':'); format_char != NULL; format_char = strchr(ether_format, ':')) *format_char = '-'; @@ -78,6 +79,48 @@ 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; + } + ether_format = ether_ntoa((const struct ether_addr *) + &ifr.ifr_addr.sa_data); + if (f_ether != NULL && strcmp(f_ether, "dash") == 0) { + for (format_char = strchr(ether_format, ':'); + format_char != NULL; + format_char = strchr(ether_format, ':')) + *format_char = '-'; + } + printf("\thwaddr %s\n", ether_format); + } } } diff --git a/sys/net/if.c b/sys/net/if.c index 12f867c..85fe24e 100644 --- a/sys/net/if.c +++ b/sys/net/if.c @@ -744,6 +744,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 && @@ -1059,6 +1064,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. */ @@ -2667,6 +2674,10 @@ ifhwioctl(u_long cmd, struct ifnet *ifp, caddr_t data, struct thread *td) ifr->ifr_addr.sa_data, ifr->ifr_addr.sa_len); break; + case SIOCGHWADDR: + error = if_gethwaddr(ifp, ifr); + break; + case SIOCAIFGROUP: { struct ifgroupreq *ifgr = (struct ifgroupreq *)ifr; @@ -3598,6 +3609,29 @@ if_requestencap_default(struct ifnet *ifp, struct if_encap_req *req) } /* + * 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 82c8b3a..71f2ee8 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 89fc2d83..a18ba1e 100644 --- a/sys/net/if_var.h +++ b/sys/net/if_var.h @@ -241,6 +241,7 @@ struct ifnet { struct ifmultihead if_multiaddrs; /* multicast addresses configured */ int if_amcount; /* number of all-multicast requests */ struct ifaddr *if_addr; /* pointer to link-level address */ + void *if_hw_addr; /* hardware link-level address */ const u_int8_t *if_broadcastaddr; /* linklevel broadcast bytestring */ struct rwlock if_afdata_lock; void *if_afdata[AF_MAX]; @@ -608,6 +609,7 @@ int if_gethwassist(if_t ifp); int if_setsoftc(if_t ifp, void *softc); void *if_getsoftc(if_t ifp); int if_setflags(if_t ifp, int flags); +int if_gethwaddr(if_t ifp, struct ifreq *); int if_setmtu(if_t ifp, int mtu); int if_getmtu(if_t ifp); int if_getmtu_family(if_t ifp, int family); diff --git a/sys/sys/sockio.h b/sys/sys/sockio.h index abdf1c3..de79041 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 */ |