/*
 * @(#)if-solaris.c from ifstatus v1.3 06 JAN 2001
 * if-solaris.c by Dave Curry davy@iss.net
 *
 * Updated 06 JAN 2001 by Rob Thomas robt@cymru.com
 * Version 1.3 - Now supports the Solaris 8 hme and qfe driver.
 */

#if defined(SUNOS55) || defined(SUNOS56) || defined(SUNOS58)

#include <sys/param.h>
#include <sys/stream.h>
#include <sys/dditypes.h>
#include <sys/ethernet.h>
#include <nlist.h>
#include <fcntl.h>
#include <stdio.h>
#include <kvm.h>

#ifdef SUNOS55
#include "if-solaris25.h"
#endif
#ifdef SUNOS56
#include "if-solaris26.h"
#endif
#ifdef SUNOS58
#include "if-solaris8.h"
#endif

struct nlist nl[] = {
#define X_IE	     0
	 { "iedev"       },
#define X_LE	     1
	 { "ledev"       },
#define X_QE	     2
	 { "qeup"        },
#define X_HME	    3
	 { "hmeup"       },
#ifdef SUNOS58
#define X_QFE	   4
	 { "qfeup"  },
#endif /* SUNOS58 */
#define X_XX	     5
	 { 0             }
};

extern char	*hostName;
extern char	*programName;

extern int	verbose;

checkInterfaces()
{
	kvm_t *kd;

	if ((kd = kvm_open(NULL, NULL, NULL, O_RDONLY, programName)) == NULL)
		fatal("kvm_open", NULL);

	if (kvm_nlist(kd, nl) < 0)
		fatal("kvm_nlist", NULL);

	if (nl[X_IE].n_value != 0) {
		if (verbose)
			fprintf(stdout, "Checking ie interfaces.\n");
		checkIE(kd);
	}

	if (nl[X_LE].n_value != 0) {
		if (verbose)
			fprintf(stdout, "Checking le interfaces.\n");
		checkLE(kd);
	}

	if (nl[X_QE].n_value != 0) {
		if (verbose)
			fprintf(stdout, "Checking qe interfaces.\n");
		checkQE(kd);
	}

	if (nl[X_HME].n_value != 0) {
		if (verbose)
			fprintf(stdout, "Checking hme interfaces.\n");
		checkHME(kd);
	}
#ifdef SUNOS58
	if (nl[X_QFE].n_value != 0) {
		if (verbose)
			fprintf(stdout, "Checking qfe interfaces.\n");
		checkQFE(kd);
	}
#endif /* SUNOS58 */
	kvm_close(kd);
}

checkIE(kd)
kvm_t *kd;
{
	 struct ie ie;
	 struct dev_info di;
	 u_long ieaddr, dipaddr;

	 ieaddr = nl[X_IE].n_value;

	 do {
	         if (kvm_read(kd, ieaddr, (char *) &ie, sizeof(struct ie)) < 0)
	                 fatal("kvm_read: ie", NULL);

	         dipaddr = (u_long) ie.ie_dip;
	         ieaddr = (u_long) ie.ie_nextp;

	         if (dipaddr == 0)
	                 continue;

	         if (kvm_read(kd, dipaddr, (char *) &di, sizeof(struct dev_info)) < 0)
	                 continue;

	         if (verbose) {
	                 printf("Interface ie%d: flags=0x%x\n",
	                        di.devi_instance, ie.ie_flags);
	         }

	         if (ie.ie_flags & IEPROMISC) {
	                 printf("WARNING: %s INTERFACE ie%d IS IN PROMISCUOUS MODE.\n",
	                        hostName, di.devi_instance);
	         }
	 } while (ieaddr != 0);
}

checkLE(kd)
kvm_t *kd;
{
	struct le le;
	struct dev_info di;
	u_long leaddr, dipaddr;

	leaddr = nl[X_LE].n_value;

	do {
		if (kvm_read(kd, leaddr, (char *) &le, sizeof(struct le)) < 0)
			fatal("kvm_read: le", NULL);

		dipaddr = (u_long) le.le_dip;
		leaddr = (u_long) le.le_nextp;

		if (dipaddr == 0)
			continue;

		if (kvm_read(kd, dipaddr, (char *) &di, sizeof(struct dev_info)) < 0)
			continue;

		if (verbose) {
			printf("Interface le%d: flags=0x%x\n",
				di.devi_instance, le.le_flags);
		}

		if (le.le_flags & LEPROMISC) {
			printf("WARNING: %s INTERFACE le%d IS IN PROMISCUOUS MODE.\n",
				hostName, di.devi_instance);
		}
	} while (leaddr != 0);
}

checkQE(kd)
kvm_t *kd;
{
	 struct qe qe;
	 struct dev_info di;
	 u_long qeaddr, dipaddr;

	 qeaddr = nl[X_QE].n_value;

	 do {
	         if (kvm_read(kd, qeaddr, (char *) &qe, sizeof(struct qe)) < 0)
	                 fatal("kvm_read: qe", NULL);

	         dipaddr = (u_long) qe.qe_dip;
	         qeaddr = (u_long) qe.qe_nextp;

	         if (dipaddr == 0)
	                 continue;

	         if (kvm_read(kd, dipaddr, (char *) &di, sizeof(struct dev_info))
 < 0)
	                 continue;

	         if (verbose) {
	                 printf("Interface qe%d: flags=0x%x\n",
	                        di.devi_instance, qe.qe_flags);
	         }

	         if (qe.qe_flags & QEPROMISC) {
	                 printf("WARNING: %s INTERFACE qe%d IS IN PROMISCUOUS MODE.\n",
	                        hostName, di.devi_instance);
	         }
	 } while (qeaddr != 0);
}

checkHME(kd)
kvm_t *kd;
{
	struct hme hme;
	struct dev_info di;
	u_long hmeaddr, dipaddr;
	hmeaddr = nl[X_HME].n_value;

	do {
		if (kvm_read(kd, hmeaddr, (char *) &hme,sizeof(struct hme)) < 0)
			fatal("kvm_read: hme", NULL);

#ifdef SUNOS58
		dipaddr = (u_long) hme.dip;
#else
		dipaddr = (u_long) hme.hme_dip;
#endif /* SUNOS58 */
		hmeaddr = (u_long) hme.hme_nextp;

		if (dipaddr == 0)
			continue;

		if (kvm_read(kd, dipaddr, (char *) &di, sizeof(struct dev_info)) < 0)
			continue;

#ifdef SUNOS58
		if (verbose) {
			printf("Interface hme%d: Promiscuous count=%d\n",
				di.devi_instance, hme.promisc_cnt);
		}

		if (hme.promisc_cnt > 0) {
			printf("WARNING: %s INTERFACE hme%d IS IN PROMISCUOUS MODE (promiscuous streams=%d).\n",
					hostName, di.devi_instance, hme.promisc_cnt);
		}
#else
		if (verbose) {
			printf("Interface hme%d: flags=0x%x\n",
					di.devi_instance, hme.hme_flags);
		}

		if (hme.hme_flags & HMEPROMISC) {
			printf("WARNING: %s INTERFACE hme%d IS IN PROMISCUOUS MODE.\n",
					hostName, di.devi_instance);
		}
#endif /* SUNOS VERSION */


	} while (hmeaddr != 0);
}

#ifdef SUNOS58
checkQFE(kd)
kvm_t *kd;
{
	struct qfe qfe;
	struct dev_info di;
	u_long hmeaddr, dipaddr;
	hmeaddr = nl[X_QFE].n_value;

	do {
		if (kvm_read(kd, hmeaddr, (char *) &qfe,sizeof(struct qfe)) < 0)
			fatal("kvm_read: hme", NULL);

                dipaddr = (u_long) qfe.hme_dip;
		hmeaddr = (u_long) qfe.hme_nextp;

		if (dipaddr == 0)
			continue;

		if (kvm_read(kd, dipaddr, (char *) &di, sizeof(struct dev_info)) < 0)
			continue;

		if (verbose) {
			printf("Interface qfe%d: Promiscuous count=%d\n",
				di.devi_instance, qfe.hme_promisc_cnt);
		}

		if (qfe.hme_promisc_cnt > 0) {
			printf("WARNING: %s INTERFACE qfe%d IS IN PROMISCUOUS MODE (promiscuous streams=%d).\n",
				hostName, di.devi_instance,
				qfe.hme_promisc_cnt);
		}
	} while (hmeaddr != 0);
}
#endif /* SUNOS58 */

#endif /* SUNOS5 */
