Author: rpokala
Date: Wed May 17 22:29:25 2017
New Revision: 318430
URL: https://svnweb.freebsd.org/changeset/base/318430

Log:
  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

Modified:
  stable/10/sbin/ifconfig/af_link.c
  stable/10/sys/net/if.c
  stable/10/sys/net/if_ethersubr.c
  stable/10/sys/net/if_var.h
  stable/10/sys/sys/sockio.h
Directory Properties:
  stable/10/   (props changed)

Modified: stable/10/sbin/ifconfig/af_link.c
==============================================================================
--- stable/10/sbin/ifconfig/af_link.c   Wed May 17 22:13:07 2017        
(r318429)
+++ stable/10/sbin/ifconfig/af_link.c   Wed May 17 22:29:25 2017        
(r318430)
@@ -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
 
                        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));
+               }
        }
 }
 

Modified: stable/10/sys/net/if.c
==============================================================================
--- stable/10/sys/net/if.c      Wed May 17 22:13:07 2017        (r318429)
+++ stable/10/sys/net/if.c      Wed May 17 22:29:25 2017        (r318430)
@@ -732,6 +732,11 @@ if_attach_internal(struct ifnet *ifp, in
                /* 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, in
                 * 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,
                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_
 }
 
 /*
+ * 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

Modified: stable/10/sys/net/if_ethersubr.c
==============================================================================
--- stable/10/sys/net/if_ethersubr.c    Wed May 17 22:13:07 2017        
(r318429)
+++ stable/10/sys/net/if_ethersubr.c    Wed May 17 22:29:25 2017        
(r318430)
@@ -918,6 +918,9 @@ ether_ifattach(struct ifnet *ifp, const 
        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);

Modified: stable/10/sys/net/if_var.h
==============================================================================
--- stable/10/sys/net/if_var.h  Wed May 17 22:13:07 2017        (r318429)
+++ stable/10/sys/net/if_var.h  Wed May 17 22:29:25 2017        (r318430)
@@ -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);

Modified: stable/10/sys/sys/sockio.h
==============================================================================
--- stable/10/sys/sys/sockio.h  Wed May 17 22:13:07 2017        (r318429)
+++ stable/10/sys/sys/sockio.h  Wed May 17 22:29:25 2017        (r318430)
@@ -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 */
_______________________________________________
svn-src-stable-10@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-stable-10
To unsubscribe, send any mail to "svn-src-stable-10-unsubscr...@freebsd.org"

Reply via email to