summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authorrpokala <rpokala@FreeBSD.org>2017-05-17 22:29:25 +0000
committerRenato Botelho <renato@netgate.com>2017-05-18 07:48:53 -0300
commitd97064d770b5fe7f4ea2dc4cd031e829b1a1a0e3 (patch)
tree249be7e31228212b398dcfd17f236ef0ba600eaa /sys
parentbbfdb9a1d32f8fbc853e0422c9916f660f048893 (diff)
downloadFreeBSD-src-d97064d770b5fe7f4ea2dc4cd031e829b1a1a0e3.zip
FreeBSD-src-d97064d770b5fe7f4ea2dc4cd031e829b1a1a0e3.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 (cherry picked from commit 2ce46e31d62424593e08c3853efe8c1e9283aba2)
Diffstat (limited to 'sys')
-rw-r--r--sys/net/if.c34
-rw-r--r--sys/net/if_ethersubr.c3
-rw-r--r--sys/net/if_var.h2
-rw-r--r--sys/sys/sockio.h1
4 files changed, 40 insertions, 0 deletions
diff --git a/sys/net/if.c b/sys/net/if.c
index 288d944..ff114b7 100644
--- a/sys/net/if.c
+++ b/sys/net/if.c
@@ -723,6 +723,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 &&
@@ -979,6 +984,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. */
@@ -2619,6 +2626,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;
@@ -3557,6 +3568,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 773918f..a15ce03 100644
--- a/sys/net/if_ethersubr.c
+++ b/sys/net/if_ethersubr.c
@@ -928,6 +928,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 1ff7a4b..57d7028 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) */
@@ -968,6 +969,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 0ad221b..9c450c3 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 addres */
#define SIOCGIFPSRCADDR _IOWR('i', 71, struct ifreq) /* get gif psrc addr */
OpenPOWER on IntegriCloud