Commit Diff


commit - e3c4ca9685cb6c571a1dff20cd7ffdd9fc13ef59
commit + 0f2907ccd2c03329079c1156cdf2974cdc4e93fe
blob - 1d7172095b8d6aa24cd51143d65e5bb280634b4e
blob + f5cf4677a95d48663795a2447b644bb23861ed22
--- complete.c
+++ complete.c
@@ -260,11 +260,11 @@ complete_ifname(char *word, int list, EditLine *el)
 	StringList *words;
 	size_t wordlen;
 	unsigned char rv;   
+	const char *status_cmd = "status";
+	struct if_nameindex *ifn_list, *ifnp;
 
 	words = sl_init();
 	wordlen = strlen(word);
-
-	struct if_nameindex *ifn_list, *ifnp;
 
 	if ((ifn_list = if_nameindex()) == NULL)
 		return 0;
@@ -275,6 +275,14 @@ complete_ifname(char *word, int list, EditLine *el)
                 if (strncmp(word, ifnp->if_name, wordlen) == 0)
                         sl_add(words, ifnp->if_name);
         }
+
+	if (wordlen <= strlen(status_cmd) &&
+	    strncmp(word, status_cmd, wordlen) == 0) {
+		char *s = strdup(status_cmd);
+		if (s == NULL)
+			err(1, "strdup");
+		sl_add(words, s);
+	}
 
         rv = complete_ambiguous(word, list, words, el);
 	if_freenameindex(ifn_list);
blob - da7b5a30346564f6d74d6cb28708265c35898d35
blob + 06e4244f301a60a0ef59c71689125fe9b577b2c9
--- externs.h
+++ externs.h
@@ -469,6 +469,11 @@ int phys_status(int, char *, char *, char *, int, int)
 int intmedia(char *, int, int, char **);
 int intmediaopt(char *, int, int, char **);
 int conf_media_status(FILE *, int, char *);
+struct ifmediareq;
+const char *get_ifm_linkstate_str(struct ifmediareq *);
+const char *get_ifm_options_str(char *, size_t, uint64_t, uint64_t *);
+const char *get_ifm_type_str(uint64_t);
+const char *get_ifm_subtype_str(uint64_t);
 
 /* passwd.c */
 #define NSHPASSWD_TEMP "/var/run/nshpasswd"
blob - 154dfdd80956f1317b4e2eefa2322caf1dc6c2b4
blob + ff37c8bb238a7c157908dcaf8a18acf7bd72bfc7
--- if.c
+++ if.c
@@ -39,6 +39,7 @@
 #include <netdb.h>
 #include <net/if_vlan_var.h>
 #include <net/if_pflow.h>
+#include <net/if_media.h>
 #include <net80211/ieee80211.h>
 #include <net80211/ieee80211_ioctl.h>
 #include <ifaddrs.h>
@@ -50,6 +51,8 @@
 #include "externs.h"
 
 char *iftype(int int_type);
+const char *get_linkstate(int, int);
+void show_int_status(char *, int);
 char *get_hwdaddr(char *ifname);
 void pack_ifaliasreq(struct ifaliasreq *, ip_t *, struct in_addr *, char *);
 void pack_in6aliasreq(struct in6_aliasreq *, ip_t *, struct in6_addr *, char *);
@@ -99,6 +102,116 @@ void imr_init(char *ifname)
 			return;
 	strlcpy (imrif, ifname, IFNAMSIZ);
 	memset (&imrsave, 0, sizeof(imrsave));
+}
+
+const char *
+get_linkstate(int mt, int link_state)
+{
+	const struct if_status_description if_status_descriptions[] =
+		LINK_STATE_DESCRIPTIONS;
+	const struct if_status_description *p;
+	static char buf[8];
+
+	for (p = if_status_descriptions; p->ifs_string != NULL; p++) {
+		if (LINK_STATE_DESC_MATCH(p, mt, link_state))
+			return (p->ifs_string);
+	}
+	snprintf(buf, sizeof(buf), "[#%d]", link_state);
+	return buf;
+}
+
+void
+show_int_status(char *ifname, int ifs)
+{
+	struct ifreq ifr;
+	struct ifmediareq ifmr;
+	int flags;
+	struct if_data if_data;
+	struct sockaddr_dl *sdl = NULL;
+	const char *link_state_desc = NULL;
+	struct ifaddrs *ifap, *ifa;
+	uint64_t *media_list = NULL, seen_options = 0;
+	const char *ifm_type = NULL, *ifm_subtype = NULL;
+	char ifm_options_current[128];
+	char ifm_options_active[128];
+
+	ifm_options_current[0] = '\0';
+	ifm_options_active[0] = '\0';
+
+	memset(&ifr, 0, sizeof(ifr));
+	strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+
+	flags = get_ifflags(ifname, ifs);
+	ifr.ifr_data = (caddr_t)&if_data;
+	if (ioctl(ifs, SIOCGIFDATA, (caddr_t)&ifr) < 0) {
+		printf("%% show_int_status: SIOCGIFDATA: %s\n",
+		    strerror(errno));
+		return;
+	}
+
+	memset(&ifmr, 0, sizeof(ifmr));
+	strlcpy(ifmr.ifm_name, ifname, sizeof(ifmr.ifm_name));
+
+	if (getifaddrs(&ifap) != 0) {
+		printf("%% show_int_status: getifaddrs: %s\n",
+		    strerror(errno));
+		return;
+	}
+	for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
+		if (ifa->ifa_addr->sa_family == AF_LINK &&
+		    (strcmp(ifname, ifa->ifa_name) == 0)) {
+			sdl = (struct sockaddr_dl *)ifa->ifa_addr;
+			link_state_desc = get_linkstate(sdl->sdl_type,
+			    if_data.ifi_link_state);
+			break;
+		}
+	}
+
+	if (ioctl(ifs, SIOCGIFMEDIA, (caddr_t)&ifmr) != -1 &&
+	    ifmr.ifm_count > 0) {
+		media_list = calloc(ifmr.ifm_count, sizeof(*media_list));
+		if (media_list == NULL) {
+			printf("%% show_int_status: calloc: %s\n",
+			    strerror(errno));
+			return;
+		}
+		ifmr.ifm_ulist = media_list;
+		if (ioctl(ifs, SIOCGIFMEDIA, (caddr_t)&ifmr) == -1) {
+			printf("%% show_int_status: SIOCGIFMEDIA: %s\n",
+			    strerror(errno));
+			return;
+		}
+		if (link_state_desc == NULL)
+			link_state_desc = get_ifm_linkstate_str(&ifmr);
+	}
+
+	/* Avoid displaying "unknown" for any non-physical interface. */
+	if (link_state_desc == NULL || strcmp(link_state_desc, "unknown") == 0)
+		link_state_desc = "-";
+
+	get_ifm_options_str(ifm_options_current, sizeof(ifm_options_current),
+	    ifmr.ifm_current, &seen_options);
+	if (IFM_OPTIONS(ifmr.ifm_current) != IFM_OPTIONS(ifmr.ifm_active)) {
+		get_ifm_options_str(ifm_options_active,
+		    sizeof(ifm_options_active), ifmr.ifm_active, &seen_options);
+	}
+
+	ifm_type = get_ifm_type_str(ifmr.ifm_active);
+	/* Avoid displaying "autoselect" for any non-physical interface. */
+	if (IFM_SUBTYPE(ifmr.ifm_active) != IFM_AUTO)
+		ifm_subtype = get_ifm_subtype_str(ifmr.ifm_active);
+
+	printf("  %-7s %-7s %-15s %s%s%s%s%s%s%s\n", ifname,
+	    (flags & IFF_UP) ? "up" : "down", link_state_desc,
+	    ifm_type ? ifm_type : "",
+	    ifm_type ? " " : "",
+	    ifm_subtype ? ifm_subtype : "",
+	    ifm_subtype ? " " : "",
+	    ifm_options_current,
+	    ifm_options_current[0] != '\0' ? " " : "",
+	    ifm_options_active[0] != '\0' ? ifm_options_active : "");
+
+	free(media_list);
 }
 
 int
@@ -124,12 +237,18 @@ show_int(int argc, char **argv)
 	if (argc == 3)
 		ifname = argv[2];
 
+	if ((ifs = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+		printf("%% show_int: %s\n", strerror(errno));
+		return(1);
+	}
+
 	/*
 	 * Show all interfaces when no ifname specified.
 	 */
 	if (ifname == NULL) {
 		if ((ifn_list = if_nameindex()) == NULL) {
 			printf("%% show_int: if_nameindex failed\n");
+			close(ifs);
 			return 0;
 		}
 		for (ifnp = ifn_list; ifnp->if_name != NULL; ifnp++) {
@@ -138,14 +257,23 @@ show_int(int argc, char **argv)
 			show_int(3, args);
 		}
 		if_freenameindex(ifn_list);
+		close(ifs);
 		return(0);
+	} else if (isprefix(ifname, "status")) {
+		if ((ifn_list = if_nameindex()) == NULL) {
+			printf("%% show_int: if_nameindex failed\n");
+			close(ifs);
+			return 0;
+		}
+		puts("% Name    Status  Link            Media");
+		for (ifnp = ifn_list; ifnp->if_name != NULL; ifnp++)
+			show_int_status(ifnp->if_name, ifs);
+		if_freenameindex(ifn_list);
+		close(ifs);
+		return(0);
 	} else if (!is_valid_ifname(ifname)) {
 		printf("%% interface %s not found\n", ifname);
-		return(1);
-	}
-
-	if ((ifs = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
-		printf("%% show_int: %s\n", strerror(errno));
+		close(ifs);
 		return(1);
 	}
 
blob - 037a038913e6643f46e1614500cba779f5060ffc
blob + 5dd1ae59534881e630104e0d7f762b8b8a732fde
--- media.c
+++ media.c
@@ -228,21 +228,69 @@ init_current_media(int s, char *ifname)
 	return(media_current);
 }
 
-const char     *
-get_media_type_string(uint64_t mword)
+const char *
+get_ifm_linkstate_str(struct ifmediareq *ifmr)
 {
+	const uint64_t ifm_status_valid_list[] = IFM_STATUS_VALID_LIST;
+	const struct ifmedia_status_description *ifms;
+	int bitno;
+
+	if ((ifmr->ifm_status & IFM_AVALID) == 0)
+		return NULL;
+
+	for (bitno = 0; ifm_status_valid_list[bitno] != 0; bitno++) {
+		for (ifms = ifm_status_descriptions;
+		    ifms->ifms_valid != 0; ifms++) {
+			if (ifms->ifms_type != IFM_TYPE(ifmr->ifm_current) ||
+			    ifms->ifms_valid != ifm_status_valid_list[bitno])
+				continue;
+			return IFM_STATUS_DESC(ifms, ifmr->ifm_status);
+		}
+	}
+
+	return NULL;
+}
+
+const char *
+get_ifm_options_str(char *buf, size_t size, uint64_t ifmw,
+    uint64_t *seen_options)
+{
 	const struct ifmedia_description *desc;
 
+	buf[0] = '\0';
+
+	/* Find options. */
+	for (desc = ifm_option_descriptions; desc->ifmt_string != NULL;
+	     desc++) {
+		if (IFM_TYPE_MATCH(desc->ifmt_word, ifmw) &&
+		  (IFM_OPTIONS(ifmw) & IFM_OPTIONS(desc->ifmt_word)) != 0 &&
+		    (*seen_options & IFM_OPTIONS(desc->ifmt_word)) == 0) {
+			if (buf[0] != '\0')
+				strlcat(buf, " ", size);
+			strlcat(buf, desc->ifmt_string, size);
+			*seen_options |= IFM_OPTIONS(desc->ifmt_word);
+		}
+	}
+
+	return buf;
+}
+
+const char *
+get_ifm_type_str(uint64_t mword)
+{
+	const struct ifmedia_description *desc;
+
 	for (desc = ifm_type_descriptions; desc->ifmt_string != NULL;
 	     desc++) {
 		if (IFM_TYPE(mword) == desc->ifmt_word)
 			return (desc->ifmt_string);
 	}
-	return ("<unknown type>");
+
+	return NULL;
 }
 
 const char     *
-get_media_subtype_string(uint64_t mword)
+get_ifm_subtype_str(uint64_t mword)
 {
 	const struct ifmedia_description *desc;
 
@@ -252,6 +300,31 @@ get_media_subtype_string(uint64_t mword)
 		    IFM_SUBTYPE(desc->ifmt_word) == IFM_SUBTYPE(mword))
 			return (desc->ifmt_string);
 	}
+
+	return NULL;
+}
+
+const char     *
+get_media_type_string(uint64_t mword)
+{
+	const char *s;
+
+	s = get_ifm_type_str(mword);
+	if (s != NULL)
+		return (s);
+
+	return ("<unknown type>");
+}
+
+const char     *
+get_media_subtype_string(uint64_t mword)
+{
+	const char *s;
+
+	s = get_ifm_subtype_str(mword);
+	if (s != NULL)
+		return (s);
+
 	return ("<unknown subtype>");
 }