Andrew spotted a potential issue with the short-circuit ordering, so
here is a newer diff.

Index: ifconfig.8
===================================================================
RCS file: /cvs/src/sbin/ifconfig/ifconfig.8,v
retrieving revision 1.385
diff -u -p -u -r1.385 ifconfig.8
--- ifconfig.8  26 Oct 2022 17:06:31 -0000      1.385
+++ ifconfig.8  24 Nov 2022 18:18:51 -0000
@@ -40,6 +40,7 @@
 .Sh SYNOPSIS
 .Nm ifconfig
 .Op Fl AaC
+.Op Fl M Ar lladdr
 .Op Ar interface
 .Op Ar address_family
 .Oo
@@ -88,6 +89,11 @@ This is the default, if no parameters ar
 Print the names of all network pseudo-devices that
 can be created dynamically at runtime using
 .Nm Cm create .
+.It Fl M Ar lladdr
+Scan the non-cloned interface list for the MAC address
+.Ar lladdr
+and print the name of that interface.
+If the MAC address is found on multiple interfaces, print nothing.
 .It Ar interface
 The
 .Ar interface
Index: ifconfig.c
===================================================================
RCS file: /cvs/src/sbin/ifconfig/ifconfig.c,v
retrieving revision 1.457
diff -u -p -u -r1.457 ifconfig.c
--- ifconfig.c  26 Oct 2022 17:06:31 -0000      1.457
+++ ifconfig.c  24 Nov 2022 19:19:55 -0000
@@ -368,6 +368,9 @@ void        wg_status(int);
 void   setignore(const char *, int);
 #endif
 
+struct if_clonereq *get_cloners(void);
+int    findmac(const char *);
+
 /*
  * Media stuff.  Whenever a media command is first performed, the
  * currently select media is grabbed for this interface.  If `media'
@@ -795,6 +798,11 @@ main(int argc, char *argv[])
                                Cflag = 1;
                                nomore = 1;
                                break;
+                       case 'M':
+                               if (argv[1] == NULL)
+                                       usage();
+                               exit (findmac(argv[1]));
+                               break;
                        default:
                                usage();
                                break;
@@ -1255,12 +1263,10 @@ clone_destroy(const char *addr, int para
                err(1, "SIOCIFDESTROY");
 }
 
-void
-list_cloners(void)
+struct if_clonereq *
+get_cloners(void)
 {
-       struct if_clonereq ifcr;
-       char *cp, *buf;
-       int idx;
+       static struct if_clonereq ifcr;
 
        memset(&ifcr, 0, sizeof(ifcr));
 
@@ -1269,12 +1275,9 @@ list_cloners(void)
        if (ioctl(sock, SIOCIFGCLONERS, &ifcr) == -1)
                err(1, "SIOCIFGCLONERS for count");
 
-       buf = calloc(ifcr.ifcr_total, IFNAMSIZ);
-       if (buf == NULL)
+       if ((ifcr.ifcr_buffer = calloc(ifcr.ifcr_total, IFNAMSIZ)) == NULL)
                err(1, "unable to allocate cloner name buffer");
-
        ifcr.ifcr_count = ifcr.ifcr_total;
-       ifcr.ifcr_buffer = buf;
 
        if (ioctl(sock, SIOCIFGCLONERS, &ifcr) == -1)
                err(1, "SIOCIFGCLONERS for names");
@@ -1285,17 +1288,30 @@ list_cloners(void)
        if (ifcr.ifcr_count > ifcr.ifcr_total)
                ifcr.ifcr_count = ifcr.ifcr_total;
 
-       qsort(buf, ifcr.ifcr_count, IFNAMSIZ,
+       return &ifcr;
+}
+
+void
+list_cloners(void)
+{
+       struct if_clonereq *ifcr;
+       char *cp, *buf;
+       int idx;
+
+       ifcr = get_cloners();
+       buf = ifcr->ifcr_buffer;
+
+       qsort(buf, ifcr->ifcr_count, IFNAMSIZ,
            (int(*)(const void *, const void *))strcmp);
 
-       for (cp = buf, idx = 0; idx < ifcr.ifcr_count; idx++, cp += IFNAMSIZ) {
+       for (cp = buf, idx = 0; idx < ifcr->ifcr_count; idx++, cp += IFNAMSIZ) {
                if (idx > 0)
                        putchar(' ');
                printf("%s", cp);
        }
 
        putchar('\n');
-       free(buf);
+       free(ifcr->ifcr_buffer);
 }
 
 #define RIDADDR 0
@@ -6614,7 +6630,7 @@ __dead void
 usage(void)
 {
        fprintf(stderr,
-           "usage: ifconfig [-AaC] [interface] [address_family] "
+           "usage: ifconfig [-AaC] [-M lladdr] [interface] [address_family] "
            "[address [dest_address]]\n"
            "\t\t[parameters]\n");
        exit(1);
@@ -6782,3 +6798,55 @@ setignore(const char *id, int param)
        /* just digest the command */
 }
 #endif
+
+int
+findmac(const char *mac)
+{
+       struct ifaddrs *ifap, *ifa;
+       const char *ifnam = NULL;
+       struct if_clonereq *ifcr;
+
+       ifcr = get_cloners();
+
+       if (getifaddrs(&ifap) != 0)
+               err(1, "getifaddrs");
+
+       for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
+               struct sockaddr_dl *sdl = (struct sockaddr_dl *)ifa->ifa_addr;
+
+               if (sdl != NULL && sdl->sdl_alen &&
+                   (sdl->sdl_type == IFT_ETHER || sdl->sdl_type == IFT_CARP)) {
+                       if (strcmp(ether_ntoa((struct ether_addr *)LLADDR(sdl)),
+                           mac) == 0) {
+                               int idx, skip = 0;
+                               char *cp;
+                               size_t len;
+
+                               /* MACs on cloned devices are ignored */
+                               for (len = 0; ifa->ifa_name[len]; len++)
+                                       if (isdigit((unsigned 
char)ifa->ifa_name[len]))
+                                               break;
+                               for (cp = ifcr->ifcr_buffer, idx = 0;
+                                   idx < ifcr->ifcr_count;
+                                   idx++, cp += IFNAMSIZ) {
+                                       if (strncmp(ifa->ifa_name, cp, len) == 
0) {
+                                               skip = 1;
+                                               break;
+                                       }
+                               }
+                               if (!skip)
+                                       ifnam = ifa->ifa_name;
+
+                               if (ifnam) {    /* same MAC on multiple ifp */
+                                       freeifaddrs(ifap);
+                                       return 1;
+                               }
+                       }
+               }
+       }
+       if (ifnam)
+               printf("%s\n", ifnam);
+       free(ifcr->ifcr_buffer);
+       freeifaddrs(ifap);
+       return 0;
+}

Reply via email to