diff -urN ../sys/arch/alpha/alpha/conf.c ./arch/alpha/alpha/conf.c
--- ../sys/arch/alpha/alpha/conf.c	Sat Mar 10 06:24:46 2001
+++ ./arch/alpha/alpha/conf.c	Thu Jun 21 17:56:37 2001
@@ -197,6 +197,9 @@
 #else
 	cdev_notdef(),			/* 51 */
 #endif
+#ifdef ALTQ
+	cdev_notdef(),			/* 52: ALTQ */
+#endif
 };
 int	nchrdev = sizeof (cdevsw) / sizeof (cdevsw[0]);
 
diff -urN ../sys/arch/i386/conf/ALTQ ./arch/i386/conf/ALTQ
--- ../sys/arch/i386/conf/ALTQ	Thu Jan  1 09:00:00 1970
+++ ./arch/i386/conf/ALTQ	Thu Jun 21 17:56:37 2001
@@ -0,0 +1,22 @@
+include	"arch/i386/conf/GENERIC"
+
+# a pseudo device needed for ALTQ
+pseudo-device	altq		# altq pseudo-device
+
+# ALTQ options
+options 	ALTQ		#alternate queueing
+options 	ALTQ_CBQ	#class based queueing
+options 	ALTQ_WFQ	#weighted fair queueing
+options 	ALTQ_FIFOQ	#fifo queueing
+options 	ALTQ_RED	#random early detection
+#options 	ALTQ_FLOWVALVE	#flowvalve for RED (needs RED)
+options 	ALTQ_RIO	#triple red for diffserv (needs RED)
+#options 	ALTQ_LOCALQ	#local use
+options 	ALTQ_HFSC	#hierarchical fair service curve
+#options 	ALTQ_ECN	#ecn extention to tcp (needs RED)
+#options 	ALTQ_IPSEC	#check ipsec in IPv4
+options 	ALTQ_CDNR	#diffserv traffic conditioner
+#options 	ALTQ_BLUE	#blue by wu-chang feng
+options 	ALTQ_PRIQ	#priority queue
+#options 	ALTQ_NOPCC	#don't use processor cycle counter
+#options 	ALTQ_DEBUG	#for debugging
diff -urN ../sys/arch/i386/i386/conf.c ./arch/i386/i386/conf.c
--- ../sys/arch/i386/i386/conf.c	Wed Apr  4 05:43:13 2001
+++ ./arch/i386/i386/conf.c	Thu Jun 21 17:59:39 2001
@@ -324,6 +324,9 @@
 	cdev_mouse_init(NWSMOUSE,	/* 68: mice */
 	    wsmouse),
 	cdev_mouse_init(NWSMUX, wsmux),	/* 69: ws multiplexor */
+#ifdef ALTQ
+	cdev_notdef(),			/* 70: ALTQ */
+#endif
 };
 int	nchrdev = sizeof(cdevsw) / sizeof(cdevsw[0]);
 
diff -urN ../sys/conf/files ./conf/files
--- ../sys/conf/files	Fri Apr 13 05:14:55 2001
+++ ./conf/files	Thu Jun 21 18:00:56 2001
@@ -284,6 +284,8 @@
 pseudo-device gif: ifnet
 pseudo-device gre: ifnet
 
+pseudo-device altq: ifnet
+
 pseudo-device sequencer
 
 pseudo-device ksyms
@@ -296,6 +298,20 @@
 file adosfs/adutil.c			adosfs
 file adosfs/advfsops.c			adosfs
 file adosfs/advnops.c			adosfs
+file altq/altq_afmap.c			altq
+file altq/altq_blue.c			altq
+file altq/altq_cbq.c			altq
+file altq/altq_cdnr.c			altq
+file altq/altq_conf.c			altq
+file altq/altq_fifoq.c			altq
+file altq/altq_hfsc.c			altq
+file altq/altq_localq.c			altq
+file altq/altq_priq.c			altq
+file altq/altq_red.c			altq
+file altq/altq_rio.c			altq
+file altq/altq_rmclass.c		altq
+file altq/altq_subr.c			altq
+file altq/altq_wfq.c			altq
 file ddb/db_access.c			ddb | kgdb
 file ddb/db_aout.c			ddb
 file ddb/db_break.c			ddb
diff -urN ../sys/dev/ic/awi.c ./dev/ic/awi.c
--- ../sys/dev/ic/awi.c	Wed Feb 21 07:29:46 2001
+++ ./dev/ic/awi.c	Thu Jun 21 17:56:37 2001
@@ -317,10 +317,11 @@
 #endif
 #ifdef __FreeBSD__
 	ifp->if_output = ether_output;
-	ifp->if_snd.ifq_maxlen = ifqmaxlen;
+	IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen);
 	memcpy(sc->sc_ec.ac_enaddr, sc->sc_mib_addr.aMAC_Address,
 	    ETHER_ADDR_LEN);
 #endif
+	IFQ_SET_READY(&ifp->if_snd);
 
 	printf("%s: IEEE802.11 %s %dMbps (firmware %s)\n",
 	    sc->sc_dev.dv_xname,
@@ -898,12 +899,7 @@
 			break;
 		m_freem(m);
 	}
-	for (;;) {
-		IF_DEQUEUE(&ifp->if_snd, m);
-		if (m == NULL)
-			break;
-		m_freem(m);
-	}
+	IFQ_PURGE(&ifp->if_snd);
 	while ((bp = TAILQ_FIRST(&sc->sc_scan)) != NULL) {
 		TAILQ_REMOVE(&sc->sc_scan, bp, list);
 		free(bp, M_DEVBUF);
@@ -982,7 +978,7 @@
 		} else {
 			if (!(ifp->if_flags & IFF_RUNNING))
 				break;
-			IF_DEQUEUE(&ifp->if_snd, m0);
+			IFQ_POLL(&ifp->if_snd, m0);
 			if (m0 == NULL)
 				break;
 			len = m0->m_pkthdr.len + sizeof(struct ieee80211_frame);
@@ -993,10 +989,10 @@
 				len += IEEE80211_WEP_IVLEN +
 				    IEEE80211_WEP_KIDLEN + IEEE80211_WEP_CRCLEN;
 			if (awi_next_txd(sc, len, &frame, &ntxd)) {
-				IF_PREPEND(&ifp->if_snd, m0);
 				ifp->if_flags |= IFF_OACTIVE;
 				break;
 			}
+			IFQ_DEQUEUE(&ifp->if_snd, m0);
 			AWI_BPF_MTAP(sc, m0, AWI_BPF_NORM);
 			m0 = awi_fix_txhdr(sc, m0);
 			if (sc->sc_wep_algo != NULL && m0 != NULL)
diff -urN ../sys/dev/ic/dc.c ./dev/ic/dc.c
--- ../sys/dev/ic/dc.c	Sun Apr 15 10:18:27 2001
+++ ./dev/ic/dc.c	Thu Jun 21 17:56:37 2001
@@ -1650,7 +1650,13 @@
 	ifp->if_start = dc_start;
 	ifp->if_watchdog = dc_watchdog;
 	ifp->if_baudrate = 10000000;
-	ifp->if_snd.ifq_maxlen = DC_TX_LIST_CNT - 1;
+	IFQ_SET_MAXLEN(&ifp->if_snd, DC_TX_LIST_CNT - 1);
+#ifdef ALTQ
+	/* dc_coal breaks the poll-and-dequeue rule,
+	   so don't enable ALTQ for those chips */
+	if ((sc->dc_flags & DC_TX_COALESCE) == 0)
+#endif
+		IFQ_SET_READY(&ifp->if_snd);
 	bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ);
 
 	/* Do MII setup. If this is a 21143, check for a PHY on the
@@ -2283,7 +2289,7 @@
 		if (mii->mii_media_status & IFM_ACTIVE &&
 		    IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) {
 			sc->dc_link++;
-			if (ifp->if_snd.ifq_head != NULL)
+			if (!IFQ_IS_EMPTY(&ifp->if_snd))
 				dc_start(ifp);
 		}
 	}
@@ -2393,7 +2399,7 @@
 	/* Re-enable interrupts. */
 	CSR_WRITE_4(sc, DC_IMR, DC_INTRS);
 
-	if (ifp->if_snd.ifq_head != NULL)
+	if (!IFQ_IS_EMPTY(&ifp->if_snd))
 		dc_start(ifp);
 
 	return (claimed);
@@ -2457,6 +2463,11 @@
 		sc->dc_ldata->dc_tx_list[cur].dc_ctl |= DC_TXCTL_FINT;
 	if (sc->dc_flags & DC_TX_USE_TX_INTR && sc->dc_cdata.dc_tx_cnt > 64)
 		sc->dc_ldata->dc_tx_list[cur].dc_ctl |= DC_TXCTL_FINT;
+#ifdef ALTQ
+	else if ((sc->dc_flags & DC_TX_USE_TX_INTR) &&
+		 TBR_IS_ENABLED(&sc->arpcom.ac_if.if_snd))
+		sc->dc_ldata->dc_tx_list[cur].dc_ctl |= DC_TXCTL_FINT;
+#endif
 	sc->dc_ldata->dc_tx_list[*txidx].dc_status = DC_TXSTAT_OWN;
 	*txidx = frag;
 
@@ -2521,24 +2532,29 @@
 	idx = sc->dc_cdata.dc_tx_prod;
 
 	while(sc->dc_cdata.dc_tx_chain[idx] == NULL) {
-		IF_DEQUEUE(&ifp->if_snd, m_head);
+		IFQ_POLL(&ifp->if_snd, m_head);
 		if (m_head == NULL)
 			break;
 
 		if (sc->dc_flags & DC_TX_COALESCE) {
+#ifdef ALTQ
+			/* note: dc_coal breaks the poll-and-dequeue rule
+			   and ALTQ is disabled in dc_attach for those chips */
+#endif
 			if (dc_coal(sc, &m_head)) {
-				IF_PREPEND(&ifp->if_snd, m_head);
 				ifp->if_flags |= IFF_OACTIVE;
 				break;
 			}
 		}
 
 		if (dc_encap(sc, m_head, &idx)) {
-			IF_PREPEND(&ifp->if_snd, m_head);
 			ifp->if_flags |= IFF_OACTIVE;
 			break;
 		}
 
+		/* now we are committed to transmit the packet */
+		IFQ_DEQUEUE(&ifp->if_snd, m_head);
+
 		/*
 		 * If there's a BPF listener, bounce a copy of this frame
 		 * to him.
@@ -2552,6 +2568,8 @@
 			break;
 		}
 	}
+	if (idx == sc->dc_cdata.dc_tx_prod)
+		return;
 
 	/* Transmit */
 	sc->dc_cdata.dc_tx_prod = idx;
@@ -2893,7 +2911,7 @@
 	dc_reset(sc);
 	dc_init(sc);
 
-	if (ifp->if_snd.ifq_head != NULL)
+	if (!IFQ_IS_EMPTY(&ifp->if_snd))
 		dc_start(ifp);
 
 	return;
diff -urN ../sys/dev/ic/dp8390.c ./dev/ic/dp8390.c
--- ../sys/dev/ic/dp8390.c	Wed Apr  4 05:44:36 2001
+++ ./dev/ic/dp8390.c	Thu Jun 21 17:56:37 2001
@@ -134,7 +134,7 @@
 		ifp->if_watchdog = dp8390_watchdog;
 	ifp->if_flags =
 	    IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS | IFF_MULTICAST;
-	ifp->if_snd.ifq_maxlen = IFQ_MAXLEN;
+	IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN);
 
 	/* Print additional info when attached. */
 	printf("%s: address %s\n", sc->sc_dev.dv_xname,
@@ -182,6 +182,7 @@
 		ifmr->ifm_status = 0;
 		return;
 	}
+	IFQ_SET_READY(&ifp->if_snd);
 
 	if (sc->sc_mediastatus)
 		(*sc->sc_mediastatus)(sc, ifmr);
@@ -449,7 +450,7 @@
 		ifp->if_flags |= IFF_OACTIVE;
 		return;
 	}
-	IF_DEQUEUE(&ifp->if_snd, m0);
+	IFQ_DEQUEUE(&ifp->if_snd, m0);
 	if (m0 == 0)
 		return;
 
diff -urN ../sys/dev/ic/elink3.c ./dev/ic/elink3.c
--- ../sys/dev/ic/elink3.c	Wed Feb 21 07:29:47 2001
+++ ./dev/ic/elink3.c	Thu Jun 21 17:56:37 2001
@@ -357,7 +357,8 @@
 	ifp->if_watchdog = epwatchdog;
 	ifp->if_flags =
 	    IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS | IFF_MULTICAST;
-	ifp->if_snd.ifq_maxlen = IFQ_MAXLEN;
+	IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN);
+	IFQ_SET_READY(&ifp->if_snd);
 
 	if_attach(ifp);
 	ether_ifattach(ifp);
@@ -988,7 +989,7 @@
 
 startagain:
 	/* Sneak a peek at the next packet */
-	m0 = ifp->if_snd.ifq_head;
+	IFQ_POLL(&ifp->if_snd, m0);
 	if (m0 == 0)
 		return;
 
@@ -1007,7 +1008,7 @@
 	if (len + pad > ETHER_MAX_LEN) {
 		/* packet is obviously too large: toss it */
 		++ifp->if_oerrors;
-		IF_DEQUEUE(&ifp->if_snd, m0);
+		IFQ_DEQUEUE(&ifp->if_snd, m0);
 		m_freem(m0);
 		goto readcheck;
 	}
@@ -1023,8 +1024,7 @@
 		bus_space_write_2(iot, ioh, EP_COMMAND,
 		    SET_TX_AVAIL_THRESH | EP_THRESH_DISABLE);
 	}
-
-	IF_DEQUEUE(&ifp->if_snd, m0);
+	IFQ_DEQUEUE(&ifp->if_snd, m0);
 	if (m0 == 0)		/* not really needed */
 		return;
 
diff -urN ../sys/dev/ic/fxp.c ./dev/ic/fxp.c
--- ../sys/dev/ic/fxp.c	Sat Apr  7 11:37:32 2001
+++ ./dev/ic/fxp.c	Thu Jun 21 17:56:37 2001
@@ -361,6 +361,7 @@
 	ifp->if_ioctl = fxp_ioctl;
 	ifp->if_start = fxp_start;
 	ifp->if_watchdog = fxp_watchdog;
+	IFQ_SET_READY(&ifp->if_snd);
 
 	printf(": %s, address %s\n", intrstr,
 	    ether_sprintf(sc->arpcom.ac_enaddr));
@@ -399,7 +400,7 @@
 	 * Let the system queue as many packets as we have available
 	 * TX descriptors.
 	 */
-	ifp->if_snd.ifq_maxlen = FXP_NTXCB - 1;
+	IFQ_SET_MAXLEN(&ifp->if_snd, FXP_NTXCB - 1);
 	ether_ifattach(ifp);
 
 	/*
@@ -628,14 +629,16 @@
 	 * NOTE: One TxCB is reserved to guarantee that fxp_mc_setup() can add
 	 *       a NOP command when needed.
 	 */
-	while (ifp->if_snd.ifq_head != NULL && sc->tx_queued < FXP_NTXCB - 1) {
+	while (!IFQ_IS_EMPTY(&ifp->if_snd) && sc->tx_queued < FXP_NTXCB - 1) {
 		struct mbuf *m, *mb_head;
 		int segment;
 
 		/*
 		 * Grab a packet to transmit.
 		 */
-		IF_DEQUEUE(&ifp->if_snd, mb_head);
+		IFQ_DEQUEUE(&ifp->if_snd, mb_head);
+		if (mb_head == NULL)
+			break;
 
 		/*
 		 * Get pointer to next available tx desc.
@@ -734,6 +737,11 @@
 	 * going again if suspended.
 	 */
 	if (txp != NULL) {
+#ifdef ALTQ
+		/* if tb regulator is used, we need tx complete interrupt */
+		if (TBR_IS_ENABLED(&ifp->if_snd))
+			txp->cb_command |= FXP_CB_COMMAND_I;
+#endif
 		fxp_scb_wait(sc);
 		CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_RESUME);
 	}
@@ -795,7 +803,7 @@
 			/*
 			 * Try to start more packets transmitting.
 			 */
-			if (ifp->if_snd.ifq_head != NULL)
+			if (!IFQ_IS_EMPTY(&ifp->if_snd))
 				fxp_start(ifp);
 		}
 		/*
diff -urN ../sys/dev/ic/midway.c ./dev/ic/midway.c
--- ../sys/dev/ic/midway.c	Tue Oct 10 07:39:24 2000
+++ ./dev/ic/midway.c	Thu Jun 21 17:56:38 2001
@@ -46,7 +46,26 @@
  *   I would also like to thank Werner for promptly answering email and being
  *   generally helpful.
  */
-
+/*
+ *  1997/12/02, major update on 1999/04/06 kjc
+ *    new features added:
+ *	- BPF support (link type is DLT_ATM_RFC1483)
+ *	  BPF understands only LLC/SNAP!! (because bpf can't
+ *	  handle variable link header length.)
+ *	  (bpfwrite should work if atm_pseudohdr and LLC/SNAP are prepended.)
+ *	- support vc shaping
+ *	- integrate IPv6 support.
+ *	- support pvc sub interface
+ *
+ *	  initial work on per-pvc-interface for ipv6 was done
+ *	  by Katsushi Kobayashi <ikob@cc.uec.ac.jp> of the WIDE Project.
+ * 	  some of the extensions for pvc subinterfaces are merged from
+ *	  the CAIRN project written by Suresh Bhogavilli (suresh@isi.edu).
+ *
+ *    code cleanup:
+ *	- remove WMAYBE related code.  ENI WMAYBE DMA doen't work.
+ *	- remove updating if_lastchange for every packet.
+ */
 
 #undef	EN_DEBUG
 #undef	EN_DEBUG_RANGE		/* check ranges on en_read/en_write's? */
@@ -112,6 +131,11 @@
 #include "en.h"
 #endif
 
+#ifdef __NetBSD__
+#include "opt_ddb.h"
+#include "opt_inet.h"
+#endif
+
 #if NEN > 0 || !defined(__FreeBSD__)
 
 #include <sys/param.h>
@@ -128,24 +152,37 @@
 #include <sys/mbuf.h>
 #include <sys/socket.h>
 #include <sys/socketvar.h>
+#include <sys/queue.h>
 
 #include <net/if.h>
 #include <net/if_atm.h>
 
 #include <vm/vm.h>
 
-#ifdef INET
+#if defined(INET) || defined(INET6)
+#include <netinet/in.h>
 #include <netinet/if_atm.h>
+#ifdef INET6
+#include <netinet6/in6_var.h>
+#endif
 #endif
 
 #ifdef NATM
+#if !(defined(INET) || defined(INET6))
 #include <netinet/in.h>
+#endif
 #include <netnatm/natm.h>
 #endif
 
-
-#if !defined(__sparc__) && !defined(__FreeBSD__)
+#if !defined(__sparc__)		/* no bus.h XXX */
+#if !defined(__FreeBSD__)
 #include <machine/bus.h>
+
+#if !defined(__OpenBSD__)
+#define LIST_FOREACH(var, head, field)					\
+	for((var) = (head)->lh_first; (var); (var) = (var)->field.le_next)
+#endif
+#endif
 #endif
 
 #if defined(__NetBSD__) || defined(__OpenBSD__)
@@ -175,6 +212,28 @@
 
 #endif	/* __FreeBSD__ */
 
+#ifdef ATM_PVCEXT
+# ifndef NATM
+   /* this is for for __KAME__ */
+#  include <netinet/in.h>
+# endif
+# if defined (__KAME__) && defined(INET6)
+#  include <netinet6/in6_ifattach.h>
+# endif
+#endif /*ATM_PVCEXT*/
+
+#include "bpfilter.h"
+#if NBPFILTER > 0
+#include <net/bpf.h>
+#ifdef __FreeBSD__
+#define BPFATTACH(ifp, dlt, hlen)	bpfattach((ifp), (dlt), (hlen))
+#define BPF_MTAP(ifp, m)		bpf_mtap((ifp), (m))
+#else
+#define BPFATTACH(ifp, dlt, hlen)	bpfattach(&(ifp)->if_bpf, (ifp), (dlt), (hlen))
+#define BPF_MTAP(ifp, m)		bpf_mtap((ifp)->if_bpf, (m))
+#endif
+#endif /* NBPFILTER > 0 */
+
 /*
  * params
  */
@@ -302,6 +361,17 @@
 STATIC INLINE	void en_write __P((struct en_softc *, u_int32_t,
 		    u_int32_t)) __attribute__ ((unused));
 
+#ifdef ATM_PVCEXT
+static void rrp_add __P((struct en_softc *, struct ifnet *));
+static struct ifnet *en_pvcattach __P((struct ifnet *));
+static int en_txctl __P((struct en_softc *, int, int, int));
+static int en_pvctx __P((struct en_softc *, struct pvctxreq *));
+static int en_pvctxget __P((struct en_softc *, struct pvctxreq *));
+static int en_pcr2txspeed __P((int));
+static int en_txspeed2pcr __P((int));
+static struct ifnet *en_vci2ifp __P((struct en_softc *, int));
+#endif
+
 /*
  * macros/inline
  */
@@ -429,9 +499,8 @@
 {
 
 #ifdef EN_DEBUG_RANGE
-  if (r > MID_MAXOFF || (r % 4)) {
-    panic("en_read: out of range, r=0x%x", r);
-  }
+  if (r > MID_MAXOFF || (r % 4))
+    panic("en_read out of range, r=0x%x", r);
 #endif
 
   return(bus_space_read_4(sc->en_memt, sc->en_base, r));
@@ -449,9 +518,8 @@
 
 {
 #ifdef EN_DEBUG_RANGE
-  if (r > MID_MAXOFF || (r % 4)) {
-    panic("en_write: out of range, r=0x%x", r);
-  }
+  if (r > MID_MAXOFF || (r % 4))
+    panic("en_write out of range, r=0x%x", r);
 #endif
 
   bus_space_write_4(sc->en_memt, sc->en_base, r, v);
@@ -709,7 +777,7 @@
 	(MID_IS_SABRE(reg)) ? "sabre controller, " : "",
 	(MID_IS_SUNI(reg)) ? "SUNI" : "Utopia",
 	(!MID_IS_SUNI(reg) && MID_IS_UPIPE(reg)) ? " (pipelined)" : "",
-	sc->en_obmemsz / 1024);
+	(u_long)sc->en_obmemsz / 1024);
 
   if (sc->is_adaptec) {
     if (sc->bestburstlen == 64 && sc->alburst == 0)
@@ -742,6 +810,7 @@
   ifp->if_ioctl = en_ioctl;
   ifp->if_output = atm_output;
   ifp->if_start = en_start;
+  IFQ_SET_READY(&ifp->if_snd);
 
   /*
    * init softc
@@ -768,6 +837,9 @@
     sz -= (EN_TXSZ * 1024);
     sc->txslot[lcv].stop = ptr;
     sc->txslot[lcv].nref = 0;
+#ifdef ATM_PVCEXT
+    sc->txrrp = NULL;
+#endif
     bzero(&sc->txslot[lcv].indma, sizeof(sc->txslot[lcv].indma));
     bzero(&sc->txslot[lcv].q, sizeof(sc->txslot[lcv].q));
 #ifdef EN_DEBUG
@@ -826,6 +898,9 @@
   printf("%s: %d %dKB receive buffers, %d %dKB transmit buffers allocated\n",
 	sc->sc_dev.dv_xname, sc->en_nrx, EN_RXSZ, EN_NTX, EN_TXSZ);
 
+  printf("%s: End Station Identifier (mac address) %s\n",
+        sc->sc_dev.dv_xname, ether_sprintf(sc->macaddr));
+
   /*
    * final commit
    */
@@ -833,6 +908,12 @@
   if_attach(ifp);
   atm_ifattach(ifp); 
 
+#if NBPFILTER > 0 
+  BPFATTACH(ifp, DLT_ATM_RFC1483, sizeof(struct atmllc));
+#endif
+#ifdef ATM_PVCEXT
+  rrp_add(sc, ifp);
+#endif
 }
 
 
@@ -1116,18 +1197,31 @@
 		break;
 #endif
 	case SIOCSIFADDR: 
+#ifdef INET6
+	case SIOCSIFADDR_IN6:
+#endif
 		ifp->if_flags |= IFF_UP;
+		switch (ifa->ifa_addr->sa_family) {
 #ifdef INET
-		if (ifa->ifa_addr->sa_family == AF_INET) {
+		case AF_INET:
 			en_reset(sc);
 			en_init(sc);
 			ifa->ifa_rtrequest = atm_rtrequest; /* ??? */
 			break;
+#endif
+#ifdef INET6
+		case AF_INET6:
+			en_reset(sc);
+			en_init(sc);
+			ifa->ifa_rtrequest = atm_rtrequest; /* ??? */
+			break;
+#endif
+		default:
+			/* what to do if not INET? */
+			en_reset(sc);
+			en_init(sc);
+			break;
 		}
-#endif /* INET */
-		/* what to do if not INET? */
-		en_reset(sc);
-		en_init(sc);
 		break;
 
 	case SIOCGIFADDR: 
@@ -1135,7 +1229,18 @@
 		break;
 
 	case SIOCSIFFLAGS: 
+#ifdef ATM_PVCEXT
+	  	/* point-2-point pvc is allowed to change if_flags */
+		if (((ifp->if_flags & IFF_UP)
+		     && !(ifp->if_flags & IFF_RUNNING))
+		||  (!(ifp->if_flags & IFF_UP)
+		     && (ifp->if_flags & IFF_RUNNING))) {
+			en_reset(sc);
+			en_init(sc);
+		}
+#else
 		error = EINVAL;
+#endif
 		break;
 
 	case SIOCSIFMTU:
@@ -1154,6 +1259,94 @@
 	    en_init(sc);
 	    break;
 
+#ifdef ATM_PVCEXT
+	case SIOCADDMULTI:
+	case SIOCDELMULTI:
+		if (ifp == &sc->enif || ifr == 0) {
+			error = EAFNOSUPPORT;	/* XXX */
+			break;
+		}
+		switch (ifr->ifr_addr.sa_family) {
+#ifdef INET
+		case AF_INET:
+			break;
+#endif
+#ifdef INET6
+		case AF_INET6:
+			break;
+#endif
+		default:
+			error = EAFNOSUPPORT;
+			break;
+		}
+		break;
+
+	case SIOCGPVCSIF:
+		if (ifp != &sc->enif) {
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+		  strcpy(ifr->ifr_name, sc->enif.if_xname);
+#else
+		  sprintf(ifr->ifr_name, "%s%d",
+			  sc->enif.if_name, sc->enif.if_unit);
+#endif
+		}
+		else
+		  error = EINVAL;
+		break;
+
+	case SIOCSPVCSIF:
+		if (ifp == &sc->enif) {
+		  struct ifnet *sifp;
+		    
+		  if ((error = suser(curproc->p_ucred, &curproc->p_acflag)) != 0)
+		    break;
+
+		  if ((sifp = en_pvcattach(ifp)) != NULL) {
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+		    strcpy(ifr->ifr_name, sifp->if_xname);
+#else
+		    sprintf(ifr->ifr_name, "%s%d",
+			    sifp->if_name, sifp->if_unit);
+#endif
+#if defined(__KAME__) && defined(INET6)
+		    /* get EUI64 for PVC, from ATM hardware interface */
+		    in6_ifattach(sifp, ifp);
+#endif
+		  }
+		  else
+		    error = ENOMEM;
+		}
+		else
+		  error = EINVAL;
+		break;
+
+	case SIOCGPVCTX:
+		error = en_pvctxget(sc, (struct pvctxreq *)data);
+		break;
+
+	case SIOCSPVCTX:
+		if ((error = suser(curproc->p_ucred, &curproc->p_acflag)) == 0)
+			error = en_pvctx(sc, (struct pvctxreq *)data);
+		break;
+
+	case SIOCGPVCFWD:
+	{
+		struct pvcfwdreq *req = (struct pvcfwdreq *)data;
+		error = pvc_set_fwd(req->pvc_ifname, req->pvc_ifname2, 2);
+		break;
+	}	
+
+	case SIOCSPVCFWD:
+	{
+		struct pvcfwdreq *req = (struct pvcfwdreq *)data;
+		if ((error = suser(curproc->p_ucred, &curproc->p_acflag)) == 0)
+			error = pvc_set_fwd(req->pvc_ifname, req->pvc_ifname2,
+					    req->pvc_op);
+		break;
+	}
+
+#endif /* ATM_PVCEXT */
+
 	default: 
 	    error = EINVAL;
 	    break;
@@ -1227,7 +1420,7 @@
   slot = sc->rxvc2slot[vci];
   if ((sc->rxslot[slot].oth_flags & (ENOTHER_FREE|ENOTHER_DRAIN)) != 0)
     return(EINVAL);
-  s = splimp();		/* block out enintr() */
+  s = splnet();		/* block out enintr() */
   oldmode = EN_READ(sc, MID_VC(vci));
   newmode = MIDV_SETMODE(oldmode, MIDV_TRASH) & ~MIDV_INSERVICE;
   EN_WRITE(sc, MID_VC(vci), (newmode | (oldmode & MIDV_INSERVICE)));
@@ -1329,6 +1522,7 @@
 	break;		/* >>> exit 'while(1)' here <<< */
       m_freem(m);
     }
+
     sc->txslot[lcv].mbsize = 0;
   }
 
@@ -1347,8 +1541,23 @@
 {
   int vc, slot;
   u_int32_t loc;
+#ifdef ATM_PVCEXT
+    struct pvcsif *pvcsif;
+#endif
 
   if ((sc->enif.if_flags & IFF_UP) == 0) {
+#ifdef ATM_PVCEXT
+    LIST_FOREACH(pvcsif, &sc->sif_list, sif_links) {
+      if (pvcsif->sif_if.if_flags & IFF_UP) {
+	/*
+	 * down the device only when there is no active pvc subinterface.
+	 * if there is, we have to go through the init sequence to reflect
+	 * the software states to the device.
+	 */
+	goto up;
+      }
+    }
+#endif
 #ifdef EN_DEBUG
     printf("%s: going down\n", sc->sc_dev.dv_xname);
 #endif
@@ -1357,10 +1566,18 @@
     return;
   }
 
+#ifdef ATM_PVCEXT
+ up:
+#endif
 #ifdef EN_DEBUG
   printf("%s: going up\n", sc->sc_dev.dv_xname);
 #endif
   sc->enif.if_flags |= IFF_RUNNING;	/* enable */
+#ifdef ATM_PVCEXT
+  LIST_FOREACH(pvcsif, &sc->sif_list, sif_links) {
+    pvcsif->sif_if.if_flags |= IFF_RUNNING;
+  }
+#endif
 
   if (sc->en_busreset)
     sc->en_busreset(sc);
@@ -1468,7 +1685,7 @@
 
 /*
  * en_start: start transmitting the next packet that needs to go out
- * if there is one.    note that atm_output() has already splimp()'d us.
+ * if there is one.    note that atm_output() has already splnet()'d us.
  */
 
 STATIC void en_start(ifp)
@@ -1481,7 +1698,6 @@
 #else
     struct en_softc *sc = (struct en_softc *) ifp->if_softc;
 #endif
-    struct ifqueue *ifq = &ifp->if_snd; /* if INPUT QUEUE */
     struct mbuf *m, *lastm, *prev;
     struct atm_pseudohdr *ap, *new_ap;
     int txchan, mlen, got, need, toadd, cellcnt, first;
@@ -1498,7 +1714,7 @@
 
     while (1) {
 
-      IF_DEQUEUE(ifq, m);
+      IFQ_DEQUEUE(&ifp->if_snd, m);
       if (m == NULL)
 	return;		/* EMPTY: >>> exit here <<< */
     
@@ -1664,6 +1880,8 @@
  * en_mfix: fix a stupid mbuf
  */
 
+#ifndef __FreeBSD__
+
 STATIC int en_mfix(sc, mm, prev)
 
 struct en_softc *sc;
@@ -1738,6 +1956,136 @@
   return(1);
 }
 
+#else /* __FreeBSD__ */
+
+STATIC int en_makeexclusive(struct en_softc *, struct mbuf **, struct mbuf *);
+
+STATIC int en_makeexclusive(sc, mm, prev)
+    struct en_softc *sc;
+    struct mbuf **mm, *prev;
+{
+    struct mbuf *m, *new;
+
+    m = *mm;
+    
+    if (m->m_flags & M_EXT) {
+	if (m->m_ext.ext_free) {
+	    /* external buffer isn't an ordinary mbuf cluster! */
+	    printf("%s: mfix: special buffer! can't make a copy!\n",
+		   sc->sc_dev.dv_xname);
+	    return (0);
+	}
+	
+	if (mclrefcnt[mtocl(m->m_ext.ext_buf)] > 1) {
+	    /* make a real copy of the M_EXT mbuf since it is shared */
+	    MGET(new, M_DONTWAIT, MT_DATA);
+	    if (!new) {
+		EN_COUNT(sc->mfixfail);
+		return(0);
+	    }
+	    if (m->m_flags & M_PKTHDR)
+		M_COPY_PKTHDR(new, m);
+	    MCLGET(new, M_DONTWAIT);
+	    if ((new->m_flags & M_EXT) == 0) {
+		m_free(new);
+		EN_COUNT(sc->mfixfail);
+		return(0);
+	    }
+	    bcopy(m->m_data, new->m_data, m->m_len);	
+	    new->m_len = m->m_len;
+	    new->m_next = m->m_next;
+	    if (prev)
+		prev->m_next = new;
+	    m_free(m);
+	    *mm = new;
+	}
+	else {
+	    /* the buffer is not shared, align the data offset using
+	       this buffer. */
+	    u_char *d = mtod(m, u_char *);
+	    int off = ((u_long)d) % sizeof(u_int32_t);
+
+	    if (off > 0) {
+		bcopy(d, d - off, m->m_len);
+		m->m_data = (caddr_t)d - off;
+	    }
+	}
+    }
+    return (1);
+}
+
+STATIC int en_mfix(sc, mm, prev)
+
+struct en_softc *sc;
+struct mbuf **mm, *prev;
+
+{
+  struct mbuf *m;
+  u_char *d, *cp;
+  int off;
+  struct mbuf *nxt;
+
+  m = *mm;
+
+  EN_COUNT(sc->mfix);			/* count # of calls */
+#ifdef EN_DEBUG
+  printf("%s: mfix mbuf m_data=0x%x, m_len=%d\n", sc->sc_dev.dv_xname,
+	m->m_data, m->m_len);
+#endif
+
+  d = mtod(m, u_char *);
+  off = ((unsigned long) d) % sizeof(u_int32_t);
+
+  if (off) {
+    if ((m->m_flags & M_EXT) == 0) {
+      bcopy(d, d - off, m->m_len);   /* ALIGN! (with costly data copy...) */
+      d -= off;
+      m->m_data = (caddr_t)d;
+    } else {
+      /* can't write to an M_EXT mbuf since it may be shared */
+      if (en_makeexclusive(sc, &m, prev) == 0)
+	  return (0);
+      *mm = m;	/* note: 'd' now invalid */
+    }
+  }
+
+  off = m->m_len % sizeof(u_int32_t);
+  if (off == 0)
+    return(1);
+
+  if (m->m_flags & M_EXT) {
+      /* can't write to an M_EXT mbuf since it may be shared */
+      if (en_makeexclusive(sc, &m, prev) == 0)
+	  return (0);
+      *mm = m;	/* note: 'd' now invalid */
+  }
+
+  d = mtod(m, u_char *) + m->m_len;
+  off = sizeof(u_int32_t) - off;
+  
+  nxt = m->m_next;
+  while (off--) {
+    if (nxt != NULL && nxt->m_len == 0) {
+	/* remove an empty mbuf.  this avoids odd byte padding to an empty
+	   last mbuf.  */
+	m->m_next = nxt = m_free(nxt);
+    }
+    if (nxt == NULL) {		/* out of data, zero fill */
+      *d++ = 0;
+      continue;			/* next "off" */
+    }
+    cp = mtod(nxt, u_char *);
+    *d++ = *cp++;
+    m->m_len++;
+    nxt->m_len--; 
+    nxt->m_data = (caddr_t)cp;
+  }
+  if (nxt != NULL && nxt->m_len == 0)
+      m->m_next = m_free(nxt);
+  return(1);
+}
+
+#endif /* __FreeBSD__ */
 
 /*
  * en_txdma: start trasmit DMA, if possible
@@ -1754,6 +2102,7 @@
   struct en_launch launch;
   int datalen = 0, dtqneed, len, ncells;
   u_int8_t *cp;
+  struct ifnet *ifp;
 
 #ifdef EN_DEBUG
   printf("%s: tx%d: starting...\n", sc->sc_dev.dv_xname, chan);
@@ -1900,7 +2249,14 @@
    */
 
   EN_COUNT(sc->launch);
-  sc->enif.if_opackets++;
+#ifdef ATM_PVCEXT
+  /* if there's a subinterface for this vci, override ifp. */
+  ifp = en_vci2ifp(sc, launch.atm_vci);
+#else
+  ifp = &sc->enif;
+#endif
+  ifp->if_opackets++;
+  
   if ((launch.atm_flags & EN_OBHDR) == 0) {
     EN_COUNT(sc->lheader);
     /* store tbd1/tbd2 in host byte order */
@@ -1913,7 +2269,27 @@
   }
 
   en_txlaunch(sc, chan, &launch);
-  
+
+#if NBPFILTER > 0
+  if (ifp->if_bpf) {
+      /*
+       * adjust the top of the mbuf to skip the pseudo atm header
+       * (and TBD, if present) before passing the packet to bpf,
+       * restore it afterwards.
+       */
+      int size = sizeof(struct atm_pseudohdr);
+      if (launch.atm_flags & EN_OBHDR)
+	  size += MID_TBD_SIZE;
+
+      launch.t->m_data += size;
+      launch.t->m_len -= size;
+
+      BPF_MTAP(ifp, launch.t);
+
+      launch.t->m_data -= size;
+      launch.t->m_len += size;
+  }
+#endif /* NBPFILTER > 0 */
   /*
    * do some housekeeping and get the next packet
    */
@@ -2309,6 +2685,7 @@
   struct en_softc *sc = (struct en_softc *) arg;
   struct mbuf *m;
   struct atm_pseudohdr ah;
+  struct ifnet *ifp;
   u_int32_t reg, kick, val, mask, chip, vci, slot, dtq, drq;
   int lcv, idx, need_softserv = 0;
 
@@ -2330,7 +2707,11 @@
 	sc->sc_dev.dv_xname, reg, MID_INTBITS);
 #ifdef EN_DEBUG
 #ifdef DDB
+#ifdef __FreeBSD__
+    Debugger("en: unexpected error");
+#else
     Debugger();
+#endif
 #endif	/* DDB */
     sc->enif.if_flags &= ~IFF_RUNNING; /* FREEZE! */
 #else
@@ -2402,7 +2783,7 @@
 	m_freem(m);
       }
       EN_WRAPADD(0, MID_DTQ_N, idx, 1);
-    }
+    };
     sc->dtq_chip = MID_DTQ_REG2A(val);	/* sync softc */
   }
 
@@ -2443,10 +2824,9 @@
           m = NULL;
         } else {
 	  IF_DEQUEUE(&sc->rxslot[slot].indma, m);
-	  if (!m) {
+	  if (!m)
 	    panic("enintr: drqsync: %s: lost mbuf in slot %d!",
-		sc->sc_dev.dv_xname, slot);
-	  }
+		  sc->sc_dev.dv_xname, slot);
         }
 	/* do something with this mbuf */
 	if (sc->rxslot[slot].oth_flags & ENOTHER_DRAIN) {  /* drain? */
@@ -2474,14 +2854,28 @@
 		sc->sc_dev.dv_xname, slot, sc->rxslot[slot].atm_vci, m,
 		EN_DQ_LEN(drq), sc->rxslot[slot].rxhand);
 #endif
-	  sc->enif.if_ipackets++;
 
-	  atm_input(&sc->enif, &ah, m, sc->rxslot[slot].rxhand);
+#ifdef ATM_PVCEXT
+	  /* if there's a subinterface for this vci, override ifp. */
+	  ifp = en_vci2ifp(sc, sc->rxslot[slot].atm_vci);
+	  ifp->if_ipackets++;
+	  m->m_pkthdr.rcvif = ifp;	/* XXX */
+#else
+	  ifp = &sc->enif;
+	  ifp->if_ipackets++;
+#endif
+
+#if NBPFILTER > 0
+	  if (ifp->if_bpf)
+	    BPF_MTAP(ifp, m);
+#endif
+
+	  atm_input(ifp, &ah, m, sc->rxslot[slot].rxhand);
 	}
 
       }
       EN_WRAPADD(0, MID_DRQ_N, idx, 1);
-    }
+    };
     sc->drq_chip = MID_DRQ_REG2A(val);	/* sync softc */
 
     if (sc->need_drqs) {	/* true if we had a DRQ shortage */
@@ -2533,7 +2927,7 @@
       printf("%s: added VCI %d to swslist\n", sc->sc_dev.dv_xname, vci);
 #endif
       }
-    }
+    };
   }
 
   /*
@@ -2559,6 +2953,28 @@
   sc->vtrash += MID_VTRASH(reg);
 #endif
 
+#ifdef ATM_PVCEXT
+  /*
+   * when the tx buffer is full, packets are left in the interface queue.
+   * (en dequeues all packets even when the tx buffer is full.)
+   * call en_start for each pvc interface using round-robin scheduling
+   * to avoid starvation.
+   */
+  if (kick) {
+    struct rrp *rrp_start;
+
+    if ((rrp_start = sc->txrrp) != NULL) {
+      while (1) {
+	en_start(sc->txrrp->ifp);
+	if (sc->txrrp->next == rrp_start)
+	  break;
+	else
+	  sc->txrrp = sc->txrrp->next;
+      }
+    }
+  }
+#endif
+
   EN_INTR_RET(1); /* for us */
 }
 
@@ -2672,10 +3088,15 @@
       mlen = 0;			/* we've got trash */
       fill = MID_RBD_SIZE;
       EN_COUNT(sc->ttrash);
+#ifdef EN_DEBUG
+      printf("RX overflow lost %d cells!\n", MID_RBD_CNT(rbd));
+#endif
     } else if (!aal5) {
       mlen = MID_RBD_SIZE + MID_CHDR_SIZE + MID_ATMDATASZ; /* 1 cell (ick!) */
       fill = 0;
     } else {
+      struct ifnet *ifp;
+
       tlen = (MID_RBD_CNT(rbd) * MID_ATMDATASZ) + MID_RBD_SIZE;
       pdu = cur + tlen - MID_PDU_SIZE;
       if (pdu >= stop)
@@ -2683,12 +3104,29 @@
       pdu = EN_READ(sc, pdu);	/* get PDU in correct byte order */
       fill = tlen - MID_RBD_SIZE - MID_PDU_LEN(pdu);
       if (fill < 0 || (rbd & MID_RBD_CRCERR) != 0) {
-        printf("%s: %s, dropping frame\n", sc->sc_dev.dv_xname,
-	    (rbd & MID_RBD_CRCERR) ? "CRC error" : "invalid AAL5 PDU length");
-        printf("%s: got %d cells (%d bytes), AAL5 len is %d bytes (pdu=0x%x)\n",
-	  sc->sc_dev.dv_xname, MID_RBD_CNT(rbd), tlen - MID_RBD_SIZE,
-		MID_PDU_LEN(pdu), pdu);
+	static int first = 1;
+
+	if (first) {
+	  printf("%s: %s, dropping frame\n", sc->sc_dev.dv_xname,
+		 (rbd & MID_RBD_CRCERR) ?
+		 "CRC error" : "invalid AAL5 PDU length");
+	  printf("%s: got %d cells (%d bytes), AAL5 len is %d bytes (pdu=0x%x)\n",
+		 sc->sc_dev.dv_xname, MID_RBD_CNT(rbd),
+		 tlen - MID_RBD_SIZE, MID_PDU_LEN(pdu), pdu);
+#ifndef EN_DEBUG
+	  printf("CRC error report disabled from now on!\n");
+	  first = 0;
+#endif
+	}
 	fill = tlen;
+
+#ifdef ATM_PVCEXT
+	ifp = en_vci2ifp(sc, vci);
+#else
+	ifp = &sc->enif;
+#endif
+	ifp->if_ierrors++;
+
       }
       mlen = tlen - fill;
     }
@@ -3090,8 +3528,8 @@
 		(sc->txslot[slot].cur - sc->txslot[slot].start)/4);
 	printf("mbsize=%d, bfree=%d\n", sc->txslot[slot].mbsize,
 		sc->txslot[slot].bfree);
-        printf("txhw: base_address=0x%x, size=%d, read=%d, descstart=%d\n",
-	  MIDX_BASE(EN_READ(sc, MIDX_PLACE(slot))), 
+        printf("txhw: base_address=0x%lx, size=%d, read=%d, descstart=%d\n",
+	  (u_long)MIDX_BASE(EN_READ(sc, MIDX_PLACE(slot))), 
 	  MIDX_SZ(EN_READ(sc, MIDX_PLACE(slot))),
 	  EN_READ(sc, MIDX_READPTR(slot)), EN_READ(sc, MIDX_DESCSTART(slot)));
       }
@@ -3146,7 +3584,6 @@
         printf("0x%x ", sc->swslist[cnt]);
       printf("\n");
     }
-
   }
   return(0);
 }
@@ -3183,5 +3620,429 @@
 }
 #endif
 
+#ifdef ATM_PVCEXT
+/*
+ * ATM PVC extention: shaper control and pvc subinterfaces
+ */
+
+/*
+ * the list of the interfaces sharing the physical device.
+ * in order to avoid starvation, the interfaces are scheduled in
+ * a round-robin fashion when en_start is called from tx complete
+ * interrupts.
+ */
+static void rrp_add(sc, ifp)
+	struct en_softc *sc;
+	struct ifnet *ifp;
+{
+	struct rrp *head, *p, *new;
+
+	head = sc->txrrp;
+	if ((p = head) != NULL) {
+		while (1) {
+			if (p->ifp == ifp) {
+				/* an entry for this ifp already exits */
+				p->nref++;
+				return;
+			}
+			if (p->next == head)
+				break;
+			p = p->next;
+		}
+	}
+	
+	/* create a new entry */
+	MALLOC(new, struct rrp *, sizeof(struct rrp), M_DEVBUF, M_WAITOK);
+	if (new == NULL) {
+		printf("en_rrp_add: malloc failed!\n");
+		return;
+	}
+
+	new->ifp = ifp;
+	new->nref = 1;
+
+	if (p == NULL) {
+		/* this is the only one in the list */
+		new->next = new;
+		sc->txrrp = new;
+	}
+	else {
+		/* add the new entry at the tail of the list */
+		new->next = p->next;
+		p->next = new;
+	}
+}
+
+#if 0 /* not used */
+static void rrp_delete(sc, ifp)
+	struct en_softc *sc;
+	struct ifnet *ifp;
+{
+	struct rrp *head, *p, *prev;
+
+	head = sc->txrrp;
+
+	prev = head;
+	if (prev == NULL) {
+		printf("rrp_delete: no list!\n");
+		return;
+	}
+	p = prev->next;
+
+	while (1) {
+		if (p->ifp == ifp) {
+			p->nref--;
+			if (p->nref > 0)
+				return;
+			/* remove this entry */
+			if (p == prev) {
+				/* this is the only entry in the list */
+				sc->txrrp = NULL;
+			}
+			else {
+				prev->next = p->next;
+				if (head == p)
+					sc->txrrp = p->next;
+			}
+			FREE(p, M_DEVBUF);
+		}
+		prev = p;
+		p = prev->next;
+		if (prev == head) {
+			printf("rrp_delete: no matching entry!\n");
+			return;
+		}
+	}
+}
+#endif
+
+static struct ifnet *
+en_vci2ifp(sc, vci)
+	struct en_softc *sc;
+	int vci;
+{
+	struct pvcsif *pvcsif;
+
+	LIST_FOREACH(pvcsif, &sc->sif_list, sif_links) {
+		if (vci == pvcsif->sif_vci)
+			return (&pvcsif->sif_if);
+	}
+	return (&sc->enif);
+}
+
+/*
+ * create and attach per pvc subinterface
+ * (currently detach is not supported)
+ */
+static struct ifnet *
+en_pvcattach(ifp)
+	struct ifnet *ifp;
+{
+	struct en_softc *sc = (struct en_softc *) ifp->if_softc;
+	struct ifnet *pvc_ifp;
+	int s;
+
+	if ((pvc_ifp = pvcsif_alloc()) == NULL)
+		return (NULL);
+
+	pvc_ifp->if_softc = sc;
+	pvc_ifp->if_ioctl = en_ioctl;
+	pvc_ifp->if_start = en_start;
+	pvc_ifp->if_flags = (IFF_POINTOPOINT|IFF_MULTICAST) |
+		(ifp->if_flags & (IFF_RUNNING|IFF_SIMPLEX|IFF_NOTRAILERS));
+	IFQ_SET_READY(&pvc_ifp->if_snd);
+
+	s = splimp();
+	LIST_INSERT_HEAD(&sc->sif_list, (struct pvcsif *)pvc_ifp, sif_links);
+	if_attach(pvc_ifp);
+	atm_ifattach(pvc_ifp);
+#ifdef __OpenBSD__
+	/* if_attach of openbsd doesn't set ifq_maxlen */
+	if (pvc_ifp->if_snd.ifq_maxlen == 0)
+		IFQ_SET_MAXLEN(&pvc_ifp->if_snd, IFQ_MAXLEN);
+#endif
+
+#if NBPFILTER > 0 
+	BPFATTACH(pvc_ifp, DLT_ATM_RFC1483, sizeof(struct atmllc));
+#endif
+#ifdef ATM_PVCEXT
+	rrp_add(sc, pvc_ifp);
+#endif
+	splx(s);
+
+	return (pvc_ifp);
+}
+
+
+/* txspeed conversion derived from linux drivers/atm/eni.c
+   by Werner Almesberger, EPFL LRC */
+static const int pre_div[] = { 4,16,128,2048 };
+
+static int en_pcr2txspeed(pcr)
+	int pcr;
+{
+	int pre, res, div;
+
+	if (pcr == 0 || pcr > 347222)
+		pre = res = 0;	/* max rate */
+	else {
+		for (pre = 0; pre < 3; pre++)
+			if (25000000/pre_div[pre]/64 <= pcr)
+				break;
+		div = pre_div[pre]*(pcr);
+#if 1
+		/*
+		 * the shaper value should be rounded down,
+		 * instead of rounded up.
+		 * (which means "res" should be rounded up.)
+		 */
+		res = (25000000 + div -1)/div - 1;
+#else
+		res = 25000000/div-1;
+#endif
+		if (res < 0)
+			res = 0;
+		if (res > 63)
+			res = 63;
+	}
+	return ((pre << 6) + res);
+}
+
+static int en_txspeed2pcr(txspeed)
+	int txspeed;
+{
+	int pre, res, pcr;
+
+	pre = (txspeed >> 6) & 0x3;
+	res = txspeed & 0x3f;
+	pcr = 25000000 / pre_div[pre] / (res+1);
+	return (pcr);
+}
+
+/*
+ * en_txctl selects a hardware transmit channel and sets the shaper value.
+ * en_txctl should be called after enabling the vc by en_rxctl
+ * since it assumes a transmit channel is already assigned by en_rxctl
+ * to the vc.
+ */
+static int en_txctl(sc, vci, joint_vci, pcr)
+	struct en_softc *sc;
+	int vci;
+	int joint_vci;
+	int pcr;
+{
+	int txspeed, txchan, s;
+
+	if (pcr)
+		txspeed = en_pcr2txspeed(pcr);
+	else
+		txspeed = 0;
+
+	s = splimp();
+	txchan = sc->txvc2slot[vci];
+	sc->txslot[txchan].nref--;
+    
+	/* select a slot */
+	if (joint_vci != 0)
+		/* use the same channel */
+		txchan = sc->txvc2slot[joint_vci];
+	else if (pcr == 0)
+		txchan = 0;
+	else {
+		for (txchan = 1; txchan < EN_NTX; txchan++) {
+			if (sc->txslot[txchan].nref == 0)
+				break;
+		}
+	}
+	if (txchan == EN_NTX) {
+#if 1
+		/* no free slot! */
+		splx(s);
+		return (ENOSPC);
+#else
+		/*
+		 * to allow multiple vc's to share a slot,
+		 * use a slot with the smallest reference count
+		 */
+		int slot = 1;
+		txchan = 1;
+		for (slot = 2; slot < EN_NTX; slot++)
+			if (sc->txslot[slot].nref < sc->txslot[txchan].nref)
+				txchan = slot;
+#endif
+	}
+
+	sc->txvc2slot[vci] = txchan;
+	sc->txslot[txchan].nref++;
+
+	/* set the shaper parameter */
+	sc->txspeed[vci] = (u_int8_t)txspeed;
+
+	splx(s);
+#ifdef EN_DEBUG
+	printf("VCI:%d PCR set to %d, tx channel %d\n", vci, pcr, txchan);
+	if (joint_vci != 0)
+		printf("  slot shared with VCI:%d\n", joint_vci);
+#endif
+	return (0);
+}
+
+static int en_pvctx(sc, pvcreq)
+	struct en_softc *sc;
+	struct pvctxreq *pvcreq;
+{
+	struct ifnet *ifp;
+	struct atm_pseudoioctl api;
+	struct atm_pseudohdr *pvc_aph, *pvc_joint;
+	int vci, joint_vci, pcr;
+	int error = 0;
+
+	/* check vpi:vci values */
+	pvc_aph = &pvcreq->pvc_aph;
+	pvc_joint = &pvcreq->pvc_joint;
+
+	vci = ATM_PH_VCI(pvc_aph);
+	joint_vci = ATM_PH_VCI(pvc_joint);
+	pcr = pvcreq->pvc_pcr;
+
+	if (ATM_PH_VPI(pvc_aph) != 0 || vci >= MID_N_VC ||
+	    ATM_PH_VPI(pvc_joint) != 0 || joint_vci >= MID_N_VC)
+		return (EADDRNOTAVAIL);
+
+	if ((ifp = ifunit(pvcreq->pvc_ifname)) == NULL)
+		return (ENXIO);
+
+	if (pcr < 0) {
+		/* negative pcr means disable the vc. */
+		if (sc->rxvc2slot[vci] == RX_NONE)
+			/* already disabled */
+			return 0;
+
+		ATM_PH_FLAGS(&api.aph) = 0;
+		ATM_PH_VPI(&api.aph) = 0;
+		ATM_PH_SETVCI(&api.aph, vci);
+		api.rxhand = NULL;
+
+		error = en_rxctl(sc, &api, 0);
+		
+		if (error == 0 && &sc->enif != ifp) {
+			/* clear vc info of this subinterface */
+			struct pvcsif *pvcsif = (struct pvcsif *)ifp;
+
+			ATM_PH_SETVCI(&api.aph, 0);
+			pvcsif->sif_aph = api.aph;
+			pvcsif->sif_vci = 0;
+		}
+		return (error);
+	}
+
+	if (&sc->enif == ifp) {
+		/* called for an en interface */
+		if (sc->rxvc2slot[vci] == RX_NONE) {
+			/* vc is not active */
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+			printf("%s: en_pvctx: rx not active! vci=%d\n",
+			       ifp->if_xname, vci);
+#else
+			printf("%s%d: en_pvctx: rx not active! vci=%d\n",
+			       ifp->if_name, ifp->if_unit, vci);
+#endif
+			return (EINVAL);
+		}
+	}
+	else {
+		/* called for a pvc subinterface */
+		struct pvcsif *pvcsif = (struct pvcsif *)ifp;
+
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+    		strcpy(pvcreq->pvc_ifname, sc->enif.if_xname);
+#else
+    		sprintf(pvcreq->pvc_ifname, "%s%d",
+			sc->enif.if_name, sc->enif.if_unit);
+#endif
+		ATM_PH_FLAGS(&api.aph) =
+			(ATM_PH_FLAGS(pvc_aph) & (ATM_PH_AAL5|ATM_PH_LLCSNAP));
+		ATM_PH_VPI(&api.aph) = 0;
+		ATM_PH_SETVCI(&api.aph, vci);
+		api.rxhand = NULL;
+		pvcsif->sif_aph = api.aph;
+		pvcsif->sif_vci = ATM_PH_VCI(&api.aph);
+
+		if (sc->rxvc2slot[vci] == RX_NONE) {
+			/* vc is not active, enable rx */
+			error = en_rxctl(sc, &api, 1);
+			if (error)
+				return error;
+		}
+		else {
+			/* vc is already active, update aph in softc */
+			sc->rxslot[sc->rxvc2slot[vci]].atm_flags =
+				ATM_PH_FLAGS(&api.aph);
+		}
+	}
+
+	error = en_txctl(sc, vci, joint_vci, pcr);
+
+	if (error == 0) {
+		if (sc->txspeed[vci] != 0)
+			pvcreq->pvc_pcr = en_txspeed2pcr(sc->txspeed[vci]);
+		else
+			pvcreq->pvc_pcr = 0;
+	}
+
+	return error;
+}
+
+static int en_pvctxget(sc, pvcreq)
+	struct en_softc *sc;
+	struct pvctxreq *pvcreq;
+{
+	struct pvcsif *pvcsif;
+	struct ifnet *ifp;
+	int vci, slot;
+
+	if ((ifp = ifunit(pvcreq->pvc_ifname)) == NULL)
+		return (ENXIO);
+
+	if (ifp == &sc->enif) {
+		/* physical interface: assume vci is specified */
+		struct atm_pseudohdr *pvc_aph;
+		
+		pvc_aph = &pvcreq->pvc_aph;
+		vci = ATM_PH_VCI(pvc_aph);
+		if ((slot = sc->rxvc2slot[vci]) == RX_NONE)
+			ATM_PH_FLAGS(pvc_aph) = 0;
+		else
+			ATM_PH_FLAGS(pvc_aph) = sc->rxslot[slot].atm_flags;
+		ATM_PH_VPI(pvc_aph) = 0;
+	}
+	else {
+		/* pvc subinterface */
+#if defined (__NetBSD__) || defined(__OpenBSD__)
+		strcpy(pvcreq->pvc_ifname, sc->enif.if_xname);
+#else
+		sprintf(pvcreq->pvc_ifname, "%s%d",
+			sc->enif.if_name, sc->enif.if_unit);
+#endif
+
+		pvcsif = (struct pvcsif *)ifp;
+		pvcreq->pvc_aph = pvcsif->sif_aph;
+		vci = pvcsif->sif_vci;
+	}
+
+	if ((slot = sc->rxvc2slot[vci]) == RX_NONE) {
+		/* vc is not active */
+		ATM_PH_FLAGS(&pvcreq->pvc_aph) = 0;
+		pvcreq->pvc_pcr = -1;
+	}
+	else if (sc->txspeed[vci])
+		pvcreq->pvc_pcr = en_txspeed2pcr(sc->txspeed[vci]);
+	else
+		pvcreq->pvc_pcr = 0;
+
+	return (0);
+}
+
+#endif /* ATM_PVCEXT */
 
 #endif /* NEN > 0 || !defined(__FreeBSD__) */
diff -urN ../sys/dev/ic/midwayreg.h ./dev/ic/midwayreg.h
--- ../sys/dev/ic/midwayreg.h	Mon Jun  7 00:39:16 1999
+++ ./dev/ic/midwayreg.h	Thu Jun 21 17:56:38 2001
@@ -1,4 +1,4 @@
-/*	$OpenBSD: midwayreg.h,v 1.8 1999/06/06 15:39:16 deraadt Exp $	*/
+/*	$NetBSD: midwayreg.h,v 1.7 1998/08/20 11:42:55 pk Exp $	*/
 
 /*
  * m i d w a y r e g . h
@@ -8,8 +8,7 @@
  *
  */
 
-#if defined(__sparc__) || defined(__FreeBSD__)
-/* XXX: gross.   netbsd/sparc doesn't have machine/bus.h yet. */
+#if defined(__FreeBSD__)
 typedef void * bus_space_tag_t;
 typedef u_int32_t pci_chipset_tag_t;
 typedef caddr_t bus_space_handle_t;
@@ -20,13 +19,12 @@
     (*(volatile u_int32_t *)((h) + (o))))
 #define bus_space_write_4(t, h, o, v)                                   \
     ((void) t, ((void)(*(volatile u_int32_t *)((h) + (o)) = (v))))
+#endif
 
 #if defined(__sparc__)
 #define vtophys(x) ((u_int32_t)(x))	/* sun4c dvma */
 #endif
 
-#endif
-
 
 #define MID_SZTOB(X) 	((X) * 256 * 4) /* size to bytes */
 #define MID_BTOSZ(X)	((X) / 256 / 4)	/* bytes to "size" */
@@ -68,6 +66,7 @@
 /*
  * prom & phy: not defined here
  */
+#define MID_ADPMACOFF	0xffc0		/* mac address offset (adaptec only) */
 
 /*
  * midway regs  (byte offsets from en_base)
diff -urN ../sys/dev/ic/midwayvar.h ./dev/ic/midwayvar.h
--- ../sys/dev/ic/midwayvar.h	Fri Mar 21 07:03:05 1997
+++ ./dev/ic/midwayvar.h	Thu Jun 21 17:56:38 2001
@@ -1,4 +1,4 @@
-/*	$OpenBSD: midwayvar.h,v 1.9 1997/03/20 22:03:05 chuck Exp $	*/
+/*	$NetBSD: midwayvar.h,v 1.9 1997/03/11 23:30:21 chuck Exp $	*/
 
 /*
  *
@@ -90,6 +90,16 @@
 
 #endif
 
+#if 1 /* for ATM_PVCEXT */
+#include <sys/queue.h>
+
+/* round-robin scheduler */
+struct rrp {
+	struct rrp *next;
+	struct ifnet *ifp;
+	int	nref;
+};
+#endif
 
 /*
  * softc
@@ -144,6 +154,10 @@
   u_int8_t txspeed[MID_N_VC];	/* speed of tx on a VC */
   u_int8_t txvc2slot[MID_N_VC]; /* map VC to slot */
 
+#if 1 /* for ATM_PVCEXT */
+  struct rrp *txrrp;		/* round-robin pointer to ifnet */
+#endif
+
   /* recv vc ctrl. (per vc).   maps VC number to recv slot */
   u_int16_t rxvc2slot[MID_N_VC];
   int en_nrx;			/* # of active rx slots */
@@ -162,6 +176,8 @@
     struct ifqueue q;		/* mbufs waiting for dma now */
   } rxslot[EN_MAXNRX];		/* recv info */
 
+  u_int8_t macaddr[6];		/* card unique mac address */
+
   /* stats */
   u_int32_t vtrash;		/* sw copy of counter */
   u_int32_t otrash;		/* sw copy of counter */
@@ -194,6 +210,10 @@
   u_int8_t bestburstmask;	/* bits to check if not multiple of burst */
   u_int8_t alburst;		/* align dma bursts? */
   u_int8_t is_adaptec;		/* adaptec version of midway? */
+
+#if 1 /* for ATM_PVCEXT */
+  LIST_HEAD(sif_list, pvcsif) sif_list;	/* pvc subinterface list */
+#endif
 };
 
 /*
diff -urN ../sys/dev/ic/pdq_ifsubr.c ./dev/ic/pdq_ifsubr.c
--- ../sys/dev/ic/pdq_ifsubr.c	Thu Oct 31 10:01:37 1996
+++ ./dev/ic/pdq_ifsubr.c	Thu Jun 21 17:56:38 2001
@@ -148,7 +148,7 @@
     ifp->if_timer = 0;
     for (;;) {
 	struct mbuf *m;
-	IF_DEQUEUE(&ifp->if_snd, m);
+	IFQ_DEQUEUE(&ifp->if_snd, m);
 	if (m == NULL)
 	    return;
 	m_freem(m);
@@ -160,7 +160,6 @@
     struct ifnet *ifp)
 {
     pdq_softc_t *sc = (pdq_softc_t *) ((caddr_t) ifp - offsetof(pdq_softc_t, sc_ac.ac_if));
-    struct ifqueue *ifq = &ifp->if_snd;
     struct mbuf *m;
     int tx = 0;
 
@@ -175,15 +174,16 @@
 	return;
     }
     for (;; tx = 1) {
-	IF_DEQUEUE(ifq, m);
+	IFQ_POLL(&ifp->if_snd, m);
 	if (m == NULL)
 	    break;
 
 	if (pdq_queue_transmit_data(sc->sc_pdq, m) == PDQ_FALSE) {
 	    ifp->if_flags |= IFF_OACTIVE;
-	    IF_PREPEND(ifq, m);
 	    break;
 	}
+
+	IFQ_DEQUEUE(&ifp->if_snd, m);
     }
     if (tx)
 	PDQ_DO_TYPE2_PRODUCER(sc->sc_pdq);
@@ -221,7 +221,7 @@
 {
     pdq_softc_t *sc = (pdq_softc_t *) pdq->pdq_os_ctx;
     sc->sc_if.if_flags &= ~IFF_OACTIVE;
-    if (sc->sc_if.if_snd.ifq_head != NULL) {
+    if (!IFQ_IS_EMPTY(&sc->sc_if.if_snd)) {
 	sc->sc_if.if_timer = PDQ_OS_TX_TIMEOUT;
 	pdq_ifstart(&sc->sc_if);
     } else {
@@ -374,6 +374,9 @@
     ifp->if_ioctl = pdq_ifioctl;
     ifp->if_output = fddi_output;
     ifp->if_start = pdq_ifstart;
+#ifdef notyet /* if_fddisubr.c hasn't been converted yet */
+    IFQ_SET_READY(&ifp->if_snd);
+#endif
   
     if_attach(ifp);
     fddi_ifattach(ifp);
diff -urN ../sys/dev/ic/rtl81x9.c ./dev/ic/rtl81x9.c
--- ../sys/dev/ic/rtl81x9.c	Sun Apr 15 10:18:28 2001
+++ ./dev/ic/rtl81x9.c	Thu Jun 21 18:03:16 2001
@@ -848,7 +848,7 @@
 	/* Re-enable interrupts. */
 	CSR_WRITE_2(sc, RL_IMR, RL_INTRS);
 
-	if (ifp->if_snd.ifq_head != NULL)
+	if (!IFQ_IS_EMPTY(&ifp->if_snd))
 		rl_start(ifp);
 
 	return (claimed);
@@ -915,16 +915,18 @@
 {
 	struct rl_softc		*sc;
 	struct mbuf		*m_head = NULL;
+	int			pkts = 0;
 
 	sc = ifp->if_softc;
 
 	while(RL_CUR_TXMBUF(sc) == NULL) {
-		IF_DEQUEUE(&ifp->if_snd, m_head);
+		IFQ_DEQUEUE(&ifp->if_snd, m_head);
 		if (m_head == NULL)
 			break;
 
 		/* Pack the data into the descriptor. */
 		rl_encap(sc, m_head);
+		pkts++;
 
 #if NBPFILTER > 0
 		/*
@@ -945,6 +947,8 @@
 
 		RL_INC(sc->rl_cdata.cur_tx);
 	}
+	if (pkts == 0)
+		return;
 
 	/*
 	 * We broke out of the loop because all our TX slots are
@@ -1274,7 +1278,8 @@
 	ifp->if_start = rl_start;
 	ifp->if_watchdog = rl_watchdog;
 	ifp->if_baudrate = 10000000;
-	ifp->if_snd.ifq_maxlen = IFQ_MAXLEN;
+	IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN);
+	IFQ_SET_READY(&ifp->if_snd);
 
 	bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ);
 
diff -urN ../sys/dev/ic/tropic.c ./dev/ic/tropic.c
--- ../sys/dev/ic/tropic.c	Tue Dec 28 06:51:35 1999
+++ ./dev/ic/tropic.c	Thu Jun 21 17:56:38 2001
@@ -352,6 +352,9 @@
 		ifp->if_start = tr_oldstart;
 	ifp->if_flags = IFF_BROADCAST | IFF_NOTRAILERS;
 	ifp->if_watchdog = tr_watchdog;
+#ifdef notyet /* if_tokensubr.c hasn't been converted yet */
+	IFQ_SET_READY(&ifp->if_snd);
+#endif
 
 	switch (MM_INB(sc, TR_MEDIAS_OFFSET)) {
 	case 0xF:
@@ -736,7 +739,7 @@
 		return;
 
 	/* if data in queue, copy mbuf chain to fast path buffers */
-	IF_DEQUEUE(&ifp->if_snd, m0);
+	IFQ_DEQUEUE(&ifp->if_snd, m0);
 
 	if (m0 == 0)
 		return;
@@ -802,9 +805,6 @@
 #endif
 }
 
-
-#define	IF_EMPTYQUEUE(queue) ((queue).ifq_head == 0)
-
 /*
  *  tr_intr - interrupt handler.  Find the cause of the interrupt and
  *  service it.
@@ -1043,7 +1043,7 @@
 					    sc->sc_dev.dv_xname);
 					ifp->if_flags &= ~IFF_RUNNING;
 					ifp->if_flags &= ~IFF_UP;
-					if_qflush(&ifp->if_snd);
+					IFQ_PURGE(&ifp->if_snd);
 					timeout(tr_reinit, sc ,hz*30);
 				}
 				else {
@@ -1117,7 +1117,7 @@
  * XXX should this be done here ?
  */
 				/* if data on send queue */
-				if (!IF_EMPTYQUEUE(ifp->if_snd))
+				if (!IFQ_IS_EMPTY(&ifp->if_snd))
 					tr_oldstart(ifp);
 				break;
 
@@ -1351,7 +1351,7 @@
  * XXX what's command here ?  command = 0x0d (always ?)
  */
 		/* if data in queue, copy mbuf chain to DHB */
-		IF_DEQUEUE(&ifp->if_snd, m0);
+		IFQ_DEQUEUE(&ifp->if_snd, m0);
 		if (m0 != 0) {
 #if NBPFILTER > 0
 			if (ifp->if_bpf)
diff -urN ../sys/dev/ic/xl.c ./dev/ic/xl.c
--- ../sys/dev/ic/xl.c	Mon Apr  9 02:58:44 2001
+++ ./dev/ic/xl.c	Thu Jun 21 17:56:38 2001
@@ -708,6 +708,7 @@
 {
 	struct mbuf		*m;
 	struct ifnet		*ifp;
+	int			error;
 
 	ifp = &sc->arpcom.ac_if;
 
@@ -725,7 +726,11 @@
 	mtod(m, unsigned char *)[15] = 0;
 	mtod(m, unsigned char *)[16] = 0xE3;
 	m->m_len = m->m_pkthdr.len = sizeof(struct ether_header) + 3;
-	IF_ENQUEUE(&ifp->if_snd, m);
+#ifdef ALTQ
+	IFQ_ENQUEUE(&ifp->if_snd, m, NULL, error);
+#else
+	IFQ_ENQUEUE(&ifp->if_snd, m, error);
+#endif
 	xl_start(ifp);
 
 	return;
@@ -1504,7 +1509,7 @@
 		}
 	}
 
-	if (ifp->if_snd.ifq_head != NULL)
+	if (!IFQ_IS_EMPTY(&ifp->if_snd))
 		(*ifp->if_start)(ifp);
 
 	return (claimed);
@@ -1666,7 +1671,7 @@
 	start_tx = sc->xl_cdata.xl_tx_free;
 
 	while(sc->xl_cdata.xl_tx_free != NULL) {
-		IF_DEQUEUE(&ifp->if_snd, m_head);
+		IFQ_DEQUEUE(&ifp->if_snd, m_head);
 		if (m_head == NULL)
 			break;
 
@@ -1822,7 +1827,7 @@
 			break;
 		}
 
-		IF_DEQUEUE(&ifp->if_snd, m_head);
+		IFQ_DEQUEUE(&ifp->if_snd, m_head);
 		if (m_head == NULL)
 			break;
 
@@ -1990,7 +1995,11 @@
 	/*
 	 * Program the multicast filter, if necessary.
 	 */
+#if 0
 	if (sc->xl_type == XL_TYPE_905B)
+#else
+	if (0)	/* xl_setmulti_hash() does not work right */
+#endif
 		xl_setmulti_hash(sc);
 	else
 		xl_setmulti(sc);
@@ -2275,7 +2284,11 @@
 			 * Multicast list has changed; set the hardware
 			 * filter accordingly.
 			 */
+#if 0
 			if (sc->xl_type == XL_TYPE_905B)
+#else
+			if (0)	/* xl_setmulti_hash() does not work right */
+#endif
 				xl_setmulti_hash(sc);
 			else
 				xl_setmulti(sc);
@@ -2325,7 +2338,7 @@
 	xl_reset(sc, 0);
 	xl_init(sc);
 
-	if (ifp->if_snd.ifq_head != NULL)
+	if (!IFQ_IS_EMPTY(&ifp->if_snd))
 		(*ifp->if_start)(ifp);
 
 	return;
@@ -2495,7 +2508,8 @@
 		ifp->if_start = xl_start;
 	ifp->if_watchdog = xl_watchdog;
 	ifp->if_baudrate = 10000000;
-	ifp->if_snd.ifq_maxlen = XL_TX_LIST_CNT - 1;
+	IFQ_SET_MAXLEN(&ifp->if_snd, XL_TX_LIST_CNT - 1);
+	IFQ_SET_READY(&ifp->if_snd);
 	bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ);
 
 	XL_SEL_WIN(3);
diff -urN ../sys/dev/pci/if_de.c ./dev/pci/if_de.c
--- ../sys/dev/pci/if_de.c	Sun Feb  4 07:56:53 2001
+++ ./dev/pci/if_de.c	Thu Jun 21 17:56:38 2001
@@ -4116,6 +4116,11 @@
     int segcnt, free;
     u_int32_t d_status;
     struct mbuf *m0;
+#if 1 /* ALTQ */
+    struct ifnet *ifp = &sc->tulip_if;
+    struct mbuf *ombuf = m;
+    int compressed = 0;
+#endif
 
 #if defined(TULIP_DEBUG)
     if ((sc->tulip_cmdmode & TULIP_CMD_TXRUN) == 0) {
@@ -4169,6 +4174,26 @@
 		 * entries that we can use for one packet, so we have
 		 * recopy it into one mbuf and then try again.
 		 */
+#if 1 /* ALTQ */
+		struct mbuf *tmp;
+		/*
+		 * tulip_mbuf_compress() frees the original mbuf.
+		 * thus, we have to remove the mbuf from the queue
+		 * before calling it.
+		 * we don't have to worry about space shortage
+		 * after compressing the mbuf since the compressed
+		 * mbuf will take only two segs.
+		 */
+		if (compressed) {
+		    /* should not happen */
+		    printf("tulip_txput: compress called twice!\n");
+		    goto finish;
+		}
+		IFQ_DEQUEUE(&ifp->if_snd, tmp);
+		if (tmp != ombuf)
+		    panic("tulip_txput: different mbuf dequeued!");
+		compressed = 1;
+#endif
 		m = tulip_mbuf_compress(m);
 		if (m == NULL)
 		    goto finish;
@@ -4235,6 +4260,16 @@
      * The descriptors have been filled in.  Now get ready
      * to transmit.
      */
+#if 1 /* ALTQ */
+    if (!compressed && (sc->tulip_flags & TULIP_TXPROBE_ACTIVE) == 0) {
+	/* remove the mbuf from the queue */
+	struct mbuf *tmp;
+	IFQ_DEQUEUE(&ifp->if_snd, tmp);
+	if (tmp != ombuf)
+	    panic("tulip_txput: different mbuf dequeued!");
+    }
+#endif
+
     IF_ENQUEUE(&sc->tulip_txq, m);
     m = NULL;
 
@@ -4593,11 +4628,19 @@
     return error;
 }
 
+#if 1 /* ALTQ */
+/*
+ * the original dequeueing policy is dequeue-and-prepend if something
+ * goes wrong.  when altq is used, it is changed to peek-and-dequeue.
+ * the modification becomes a bit complicated since tulip_txput() might
+ * copy and modify the mbuf passed.
+ */
+#endif
 /*
  * These routines gets called at device spl (from ether_output).  This might
  * pose a problem for TULIP_USE_SOFTINTR if ether_output is called at
  * device spl from another driver.
-	 */
+ */
 
 static ifnet_ret_t
 tulip_ifstart(
@@ -4611,15 +4654,23 @@
 	if ((sc->tulip_flags & (TULIP_WANTSETUP|TULIP_TXPROBE_ACTIVE)) == TULIP_WANTSETUP)
 	    tulip_txput_setup(sc);
 
-	while (sc->tulip_if.if_snd.ifq_head != NULL) {
-	    struct mbuf *m;
-	    IF_DEQUEUE(&sc->tulip_if.if_snd, m);
-	    if ((m = tulip_txput(sc, m)) != NULL) {
-		IF_PREPEND(&sc->tulip_if.if_snd, m);
+	while (!IFQ_IS_EMPTY(&sc->tulip_if.if_snd)) {
+	    struct mbuf *m, *m0;
+	    IFQ_POLL(&sc->tulip_if.if_snd, m);
+	    if (m == NULL)
+		break;
+	    if ((m0 = tulip_txput(sc, m)) != NULL) {
+		if (m0 != m)
+		    /* should not happen */
+		    printf("tulip_if_start: txput failed!\n");
 		break;
 	    }
 	}
-	if (sc->tulip_if.if_snd.ifq_head == NULL)
+#ifdef ALTQ
+	if (0) /* don't switch to the one packet mode */
+#else
+	if (IFQ_IS_EMPTY(&sc->tulip_if.if_snd))
+#endif
 	    sc->tulip_if.if_start = tulip_ifstart_one;
     }
 
@@ -4634,11 +4685,13 @@
     tulip_softc_t * const sc = TULIP_IFP_TO_SOFTC(ifp);
 
     if ((sc->tulip_if.if_flags & IFF_RUNNING)
-	    && sc->tulip_if.if_snd.ifq_head != NULL) {
-	struct mbuf *m;
-	IF_DEQUEUE(&sc->tulip_if.if_snd, m);
-	if ((m = tulip_txput(sc, m)) != NULL)
-	    IF_PREPEND(&sc->tulip_if.if_snd, m);
+	    && !IFQ_IS_EMPTY(&sc->tulip_if.if_snd)) {
+	struct mbuf *m, *m0;
+	IFQ_POLL(&sc->tulip_if.if_snd, m);
+	if (m != NULL && (m0 = tulip_txput(sc, m)) != NULL)
+	    if (m0 != m)
+		/* should not happen */
+		printf("tulip_if_start_one: txput failed!\n");
     }
     TULIP_PERFEND(ifstart_one);
 }
@@ -4837,6 +4890,7 @@
 
     tulip_reset(sc);
 
+    IFQ_SET_READY(&ifp->if_snd);
 #if defined(__bsdi__) && _BSDI_VERSION >= 199510
     sc->tulip_pf = printf;
     TULIP_ETHER_IFATTACH(sc);
diff -urN ../sys/dev/pci/if_en_pci.c ./dev/pci/if_en_pci.c
--- ../sys/dev/pci/if_en_pci.c	Sat Apr  7 11:37:36 2001
+++ ./dev/pci/if_en_pci.c	Thu Jun 21 17:56:38 2001
@@ -77,6 +77,15 @@
  * local defines (PCI specific stuff)
  */
 
+#if !defined(MIDWAY_ENIONLY)
+static  void eni_get_macaddr __P((struct en_pci_softc *,
+		struct pci_attach_args *));
+#endif
+#if !defined(MIDWAY_ADPONLY)
+static  void adp_get_macaddr __P((struct en_pci_softc *,
+		struct pci_attach_args *));
+#endif
+
 /* 
  * address of config base memory address register in PCI config space
  * (this is card specific)
@@ -109,7 +118,7 @@
  * prototypes
  */
 
-#ifdef __BROKEN_INDIRECT_CONFIG
+#ifdef __OpenBSD__
 static	int en_pci_match __P((struct device *, void *, void *));
 #else
 static	int en_pci_match __P((struct device *, struct cfdata *, void *));
@@ -162,7 +171,7 @@
 static int en_pci_match(parent, match, aux)
 
 struct device *parent;
-#ifdef __BROKEN_INDIRECT_CONFIG
+#ifdef __OpenBSD__
 void *match;
 #else
 struct cfdata *match;
@@ -252,6 +261,7 @@
 
 #if !defined(MIDWAY_ENIONLY)
   if (sc->is_adaptec) {
+    adp_get_macaddr(scp, pa);
     sc->en_busreset = adp_busreset;
     adp_busreset(sc);
   }
@@ -259,6 +269,7 @@
 
 #if !defined(MIDWAY_ADPONLY)
   if (!sc->is_adaptec) {
+    eni_get_macaddr(scp, pa);
     sc->en_busreset = NULL;
     pci_conf_write(scp->en_pc, pa->pa_tag, EN_TONGA, 
 		  (TONGA_SWAP_DMA|TONGA_SWAP_WORD));
@@ -272,3 +283,140 @@
   en_attach(sc);
 
 }
+
+#if 0
+static void
+en_pci_shutdown(
+	int howto,
+	void *sc)
+{
+    struct en_pci_softc *psc = (struct en_pci_softc *)sc;
+    
+    en_reset(&psc->esc);
+    DELAY(10);
+}
+#endif
+
+#if !defined(MIDWAY_ENIONLY)
+
+#if defined(sparc) || defined(__FreeBSD__)
+#define bus_space_read_1(t, h, o) \
+  		((void)t, (*(volatile u_int8_t *)((h) + (o))))
+#endif
+
+static void 
+adp_get_macaddr(scp, pa)
+     struct en_pci_softc *scp;
+     struct pci_attach_args *pa;
+{
+  struct en_softc * sc = (struct en_softc *)scp;
+  int lcv;
+
+  for (lcv = 0; lcv < sizeof(sc->macaddr); lcv++)
+    sc->macaddr[lcv] = bus_space_read_1(sc->en_memt, sc->en_base,
+					MID_ADPMACOFF + lcv);
+}
+
+#endif /* MIDWAY_ENIONLY */
+
+#if !defined(MIDWAY_ADPONLY)
+
+/*
+ * Read station (MAC) address from serial EEPROM.
+ * derived from linux drivers/atm/eni.c by Werner Almesberger, EPFL LRC.
+ */
+#define EN_PROM_MAGIC  0x0c
+#define EN_PROM_DATA   0x02
+#define EN_PROM_CLK    0x01
+#define EN_ESI         64
+
+static void 
+eni_get_macaddr(scp, pa)
+  struct en_pci_softc *scp;
+  struct pci_attach_args *pa;
+{
+  struct en_softc *sc = (struct en_softc *)scp;
+  pci_chipset_tag_t id = scp->en_pc;
+  pcitag_t tag = pa->pa_tag;
+  int i, j, address, status;
+  u_int32_t data, t_data;
+  u_int8_t tmp;
+  
+  t_data = pci_conf_read(id, tag, EN_TONGA) & 0xffffff00;
+
+  data =  EN_PROM_MAGIC | EN_PROM_DATA | EN_PROM_CLK;
+  pci_conf_write(id, tag, EN_TONGA, data);
+
+  for (i = 0; i < sizeof(sc->macaddr); i ++){
+    /* start operation */
+    data |= EN_PROM_DATA ;
+    pci_conf_write(id, tag, EN_TONGA, data);
+    data |= EN_PROM_CLK ;
+    pci_conf_write(id, tag, EN_TONGA, data);
+    data &= ~EN_PROM_DATA ;
+    pci_conf_write(id, tag, EN_TONGA, data);
+    data &= ~EN_PROM_CLK ;
+    pci_conf_write(id, tag, EN_TONGA, data);
+    /* send address with serial line */
+    address = ((i + EN_ESI) << 1) + 1;
+    for ( j = 7 ; j >= 0 ; j --){
+      data = (address >> j) & 1 ? data | EN_PROM_DATA :
+      data & ~EN_PROM_DATA;
+      pci_conf_write(id, tag, EN_TONGA, data);
+      data |= EN_PROM_CLK ;
+      pci_conf_write(id, tag, EN_TONGA, data);
+      data &= ~EN_PROM_CLK ;
+      pci_conf_write(id, tag, EN_TONGA, data);
+    }
+    /* get ack */
+    data |= EN_PROM_DATA ;
+    pci_conf_write(id, tag, EN_TONGA, data);
+    data |= EN_PROM_CLK ;
+    pci_conf_write(id, tag, EN_TONGA, data);
+    data = pci_conf_read(id, tag, EN_TONGA);
+    status = data & EN_PROM_DATA;
+    data &= ~EN_PROM_CLK ;
+    pci_conf_write(id, tag, EN_TONGA, data);
+    data |= EN_PROM_DATA ;
+    pci_conf_write(id, tag, EN_TONGA, data);
+
+    tmp = 0;
+
+    for ( j = 7 ; j >= 0 ; j --){
+      tmp <<= 1;
+      data |= EN_PROM_DATA ;
+      pci_conf_write(id, tag, EN_TONGA, data);
+      data |= EN_PROM_CLK ;
+      pci_conf_write(id, tag, EN_TONGA, data);
+      data = pci_conf_read(id, tag, EN_TONGA);
+      if(data & EN_PROM_DATA) tmp |= 1;
+      data &= ~EN_PROM_CLK ;
+      pci_conf_write(id, tag, EN_TONGA, data);
+      data |= EN_PROM_DATA ;
+      pci_conf_write(id, tag, EN_TONGA, data);
+    }
+    /* get ack */
+    data |= EN_PROM_DATA ;
+    pci_conf_write(id, tag, EN_TONGA, data);
+    data |= EN_PROM_CLK ;
+    pci_conf_write(id, tag, EN_TONGA, data);
+    data = pci_conf_read(id, tag, EN_TONGA);
+    status = data & EN_PROM_DATA;
+    data &= ~EN_PROM_CLK ;
+    pci_conf_write(id, tag, EN_TONGA, data);
+    data |= EN_PROM_DATA ;
+    pci_conf_write(id, tag, EN_TONGA, data);
+
+    sc->macaddr[i] = tmp;
+  }
+  /* stop operation */
+  data &=  ~EN_PROM_DATA;
+  pci_conf_write(id, tag, EN_TONGA, data);
+  data |=  EN_PROM_CLK;
+  pci_conf_write(id, tag, EN_TONGA, data);
+  data |=  EN_PROM_DATA;
+  pci_conf_write(id, tag, EN_TONGA, data);
+  pci_conf_write(id, tag, EN_TONGA, t_data);
+}
+
+#endif /* !MIDWAY_ADPONLY */
diff -urN ../sys/dev/pci/if_lmc.c ./dev/pci/if_lmc.c
--- ../sys/dev/pci/if_lmc.c	Thu Apr 27 09:32:09 2000
+++ ./dev/pci/if_lmc.c	Thu Jun 21 17:56:38 2001
@@ -1286,15 +1286,20 @@
 lmc_ifstart(struct ifnet * const ifp)
 {
 	lmc_softc_t * const sc = LMC_IFP_TO_SOFTC(ifp);
-	struct mbuf *m;
+	struct mbuf *m, *m0;
 
 	if (sc->lmc_flags & LMC_IFUP) {
 		while (sppp_isempty(ifp) == 0) {
-			m = sppp_dequeue(ifp);
-			if ((m = lmc_txput(sc, m)) != NULL) {
-				IF_PREPEND(&((struct sppp *)ifp)->pp_fastq, m);
+			m = sppp_pick(ifp);
+			if (m == NULL)
+				break;
+			if ((m = lmc_txput(sc, m)) != NULL)
 				break;
-			}
+			m0 = sppp_dequeue(ifp);
+#if defined(LMC_DEBUG)
+			if (m0 != m)
+				printf("lmc_ifstart: mbuf mismatch!\n");
+#endif
 		}
 		LMC_CSR_WRITE(sc, csr_txpoll, 1);
 	}
@@ -1304,13 +1309,17 @@
 lmc_ifstart_one(struct ifnet * const ifp)
 {
 	lmc_softc_t * const sc = LMC_IFP_TO_SOFTC(ifp);
-	struct mbuf *m;
+	struct mbuf *m, *m0;
 
 	if ((sc->lmc_flags & LMC_IFUP) && (sppp_isempty(ifp) == 0)) {
-		m = sppp_dequeue(ifp);
-		if ((m = lmc_txput(sc, m)) != NULL) {
-			IF_PREPEND(&((struct sppp *)ifp)->pp_fastq, m);
-		}
+		m = sppp_pick(ifp);
+		if ((m = lmc_txput(sc, m)) != NULL)
+			return;
+		m0 = sppp_dequeue(ifp);
+#if defined(LMC_DEBUG)
+		if (m0 != m)
+			printf("lmc_ifstart: mbuf mismatch!\n");
+#endif
 		LMC_CSR_WRITE(sc, csr_txpoll, 1);
 	}
 }
@@ -1428,6 +1437,7 @@
 	ifp->if_watchdog = lmc_watchdog;
 	ifp->if_timer = 1;
 	ifp->if_mtu = LMC_MTU;
+	IFQ_SET_READY(&ifp->if_snd);
 
 #if defined(__bsdi__)
 	ifp->if_type = IFT_NONE;
diff -urN ../sys/dev/pci/if_ti.c ./dev/pci/if_ti.c
--- ../sys/dev/pci/if_ti.c	Wed Apr  4 05:44:43 2001
+++ ./dev/pci/if_ti.c	Thu Jun 21 17:56:48 2001
@@ -1683,7 +1683,8 @@
 	ifp->if_start = ti_start;
 	ifp->if_watchdog = ti_watchdog;
 	ifp->if_mtu = ETHERMTU;
-	ifp->if_snd.ifq_maxlen = TI_TX_RING_CNT - 1;
+	IFQ_SET_MAXLEN(&ifp->if_snd, TI_TX_RING_CNT - 1);
+	IFQ_SET_READY(&ifp->if_snd);
 	bcopy(sc->sc_dv.dv_xname, ifp->if_xname, IFNAMSIZ);
 
 	/* Set up ifmedia support. */
@@ -1946,7 +1947,7 @@
 	/* Re-enable interrupts. */
 	CSR_WRITE_4(sc, TI_MB_HOSTINTR, 0);
 
-	if (ifp->if_flags & IFF_RUNNING && ifp->if_snd.ifq_head != NULL)
+	if (ifp->if_flags & IFF_RUNNING && !IFQ_IS_EMPTY(&ifp->if_snd))
 		ti_start(ifp);
 
 	return (1);
@@ -2070,13 +2071,14 @@
 	struct ti_softc		*sc;
 	struct mbuf		*m_head = NULL;
 	u_int32_t		prodidx = 0;
+	int			pkts = 0;
 
 	sc = ifp->if_softc;
 
 	prodidx = CSR_READ_4(sc, TI_MB_SENDPROD_IDX);
 
 	while(sc->ti_cdata.ti_tx_chain[prodidx] == NULL) {
-		IF_DEQUEUE(&ifp->if_snd, m_head);
+		IFQ_POLL(&ifp->if_snd, m_head);
 		if (m_head == NULL)
 			break;
 
@@ -2086,11 +2088,14 @@
 		 * for the NIC to drain the ring.
 		 */
 		if (ti_encap(sc, m_head, &prodidx)) {
-			IF_PREPEND(&ifp->if_snd, m_head);
 			ifp->if_flags |= IFF_OACTIVE;
 			break;
 		}
 
+		/* now we are committed to transmit the packet */
+		IFQ_DEQUEUE(&ifp->if_snd, m_head);
+		pkts++;
+
 		/*
 		 * If there's a BPF listener, bounce a copy of this frame
 		 * to him.
@@ -2100,6 +2105,8 @@
 			bpf_mtap(ifp->if_bpf, m_head);
 #endif
 	}
+	if (pkts == 0)
+		return;
 
 	/* Transmit */
 	CSR_WRITE_4(sc, TI_MB_SENDPROD_IDX, prodidx);
diff -urN ../sys/dev/pci/if_tl.c ./dev/pci/if_tl.c
--- ../sys/dev/pci/if_tl.c	Fri Apr  6 05:13:47 2001
+++ ./dev/pci/if_tl.c	Thu Jun 21 18:05:07 2001
@@ -1395,7 +1395,7 @@
 		CMD_PUT(sc, TL_CMD_ACK | r | type);
 	}
 
-	if (ifp->if_snd.ifq_head != NULL)
+	if (!IFQ_IS_EMPTY(&ifp->if_snd))
 		tl_start(ifp);
 
 	return r;
@@ -1571,7 +1571,7 @@
 	start_tx = sc->tl_cdata.tl_tx_free;
 
 	while(sc->tl_cdata.tl_tx_free != NULL) {
-		IF_DEQUEUE(&ifp->if_snd, m_head);
+		IFQ_DEQUEUE(&ifp->if_snd, m_head);
 		if (m_head == NULL)
 			break;
 
@@ -2154,7 +2154,8 @@
 	ifp->if_start = tl_start;
 	ifp->if_watchdog = tl_watchdog;
 	ifp->if_baudrate = 10000000;
-	ifp->if_snd.ifq_maxlen = TL_TX_LIST_CNT - 1;
+	IFQ_SET_MAXLEN(&ifp->if_snd, TL_TX_LIST_CNT - 1);
+	IFQ_SET_READY(&ifp->if_snd);
 	bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ);
 
 	/*
diff -urN ../sys/dev/pci/if_tx.c ./dev/pci/if_tx.c
--- ../sys/dev/pci/if_tx.c	Wed Apr  4 05:44:43 2001
+++ ./dev/pci/if_tx.c	Thu Jun 21 17:56:48 2001
@@ -447,7 +447,8 @@
 	ifp->if_init = (if_init_f_t*)epic_init;
 	ifp->if_timer = 0;
 	ifp->if_baudrate = 10000000;
-	ifp->if_snd.ifq_maxlen = TX_RING_SIZE - 1;
+	IFQ_SET_MAXLEN(&ifp->if_snd, TX_RING_SIZE - 1);
+	IFQ_SET_READY(&ifp->if_snd);
 
 	/* Enable ports, memory and busmastering */
 	command = pci_read_config(dev, PCIR_COMMAND, 4);
@@ -819,7 +820,7 @@
 		flist = sc->tx_flist + sc->cur_tx;
 
 		/* Get next packet to send */
-		IF_DEQUEUE( &ifp->if_snd, m0 );
+		IFQ_DEQUEUE( &ifp->if_snd, m0 );
 
 		/* If nothing to send, return */
 		if( NULL == m0 ) return;
@@ -1038,7 +1039,7 @@
         if( status & (INTSTAT_TXC|INTSTAT_TCC|INTSTAT_TQE) ) {
             epic_tx_done( sc );
 	    if(!(sc->sc_if.if_flags & IFF_OACTIVE) &&
-		sc->sc_if.if_snd.ifq_head )
+		!IFQ_IS_EMPTY( &sc->sc_if.if_snd ))
 		    epic_ifstart( &sc->sc_if );
 	}
 
@@ -1128,7 +1129,7 @@
 		printf("seems we can continue normaly\n");
 
 	/* Start output */
-	if( ifp->if_snd.ifq_head ) epic_ifstart( ifp );
+	if( !IFQ_IS_EMPTY( &ifp->if_snd ) ) epic_ifstart( ifp );
 
 	splx(x);
 }
diff -urN ../sys/dev/pci/if_vr.c ./dev/pci/if_vr.c
--- ../sys/dev/pci/if_vr.c	Wed Apr  4 05:44:43 2001
+++ ./dev/pci/if_vr.c	Thu Jun 21 17:56:48 2001
@@ -759,6 +759,7 @@
 	ifp->if_start = vr_start;
 	ifp->if_watchdog = vr_watchdog;
 	ifp->if_baudrate = 10000000;
+	IFQ_SET_READY(&ifp->if_snd);
 	bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ);
 
 	/*
@@ -1181,7 +1182,7 @@
 	/* Re-enable interrupts. */
 	CSR_WRITE_2(sc, VR_IMR, VR_INTRS);
 
-	if (ifp->if_snd.ifq_head != NULL) {
+	if (!IFQ_IS_EMPTY(&ifp->if_snd)) {
 		vr_start(ifp);
 	}
 
@@ -1287,7 +1288,7 @@
 	start_tx = sc->vr_cdata.vr_tx_free;
 
 	while(sc->vr_cdata.vr_tx_free->vr_mbuf == NULL) {
-		IF_DEQUEUE(&ifp->if_snd, m_head);
+		IFQ_DEQUEUE(&ifp->if_snd, m_head);
 		if (m_head == NULL)
 			break;
 
@@ -1538,7 +1539,7 @@
 	vr_reset(sc);
 	vr_init(sc);
 
-	if (ifp->if_snd.ifq_head != NULL)
+	if (!IFQ_IS_EMPTY(&ifp->if_snd))
 		vr_start(ifp);
 
 	return;
diff -urN ../sys/dev/pci/if_wb.c ./dev/pci/if_wb.c
--- ../sys/dev/pci/if_wb.c	Wed Feb 21 07:29:58 2001
+++ ./dev/pci/if_wb.c	Thu Jun 21 17:56:48 2001
@@ -903,7 +903,9 @@
 	ifp->if_start = wb_start;
 	ifp->if_watchdog = wb_watchdog;
 	ifp->if_baudrate = 10000000;
-	ifp->if_snd.ifq_maxlen = WB_TX_LIST_CNT - 1;
+	IFQ_SET_MAXLEN(&ifp->if_snd, WB_TX_LIST_CNT - 1);
+	IFQ_SET_READY(&ifp->if_snd);
+
 	bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ);
 
 	/*
@@ -1310,7 +1312,7 @@
 	/* Re-enable interrupts. */
 	CSR_WRITE_4(sc, WB_IMR, WB_INTRS);
 
-	if (ifp->if_snd.ifq_head != NULL) {
+	if (!IFQ_IS_EMPTY(&ifp->if_snd)) {
 		wb_start(ifp);
 	}
 
@@ -1449,7 +1451,7 @@
 	start_tx = sc->wb_cdata.wb_tx_free;
 
 	while(sc->wb_cdata.wb_tx_free->wb_mbuf == NULL) {
-		IF_DEQUEUE(&ifp->if_snd, m_head);
+		IFQ_DEQUEUE(&ifp->if_snd, m_head);
 		if (m_head == NULL)
 			break;
 
@@ -1752,7 +1754,7 @@
 	wb_reset(sc);
 	wb_init(sc);
 
-	if (ifp->if_snd.ifq_head != NULL)
+	if (!IFQ_IS_EMPTY(&ifp->if_snd))
 		wb_start(ifp);
 
 	return;
diff -urN ../sys/dev/pcmcia/if_wi.c ./dev/pcmcia/if_wi.c
--- ../sys/dev/pcmcia/if_wi.c	Tue Apr 24 06:18:48 2001
+++ ./dev/pcmcia/if_wi.c	Thu Jun 21 17:56:48 2001
@@ -422,7 +422,8 @@
 	ifp->if_start = wi_start;
 	ifp->if_watchdog = wi_watchdog;
 	ifp->if_baudrate = 10000000;
-	ifp->if_snd.ifq_maxlen = IFQ_MAXLEN;
+	IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN);
+	IFQ_SET_READY(&ifp->if_snd);
 
 	bzero(sc->wi_node_name, sizeof(sc->wi_node_name));
 	bcopy(WI_DEFAULT_NODENAME, sc->wi_node_name,
@@ -612,7 +613,7 @@
 	/* Re-enable interrupts. */
 	CSR_WRITE_2(sc, WI_INT_EN, WI_INTRS);
 
-	if (ifp->if_snd.ifq_head != NULL)
+	if (!IFQ_IS_EMPTY(&ifp->if_snd))
 		wi_start(ifp);
 
 	return (1);
@@ -1568,7 +1569,7 @@
 	if (ifp->if_flags & IFF_OACTIVE)
 		return;
 
-	IF_DEQUEUE(&ifp->if_snd, m0);
+	IFQ_DEQUEUE(&ifp->if_snd, m0);
 	if (m0 == NULL)
 		return;
 
diff -urN ../sys/net/if.c ./net/if.c
--- ../sys/net/if.c	Wed Feb 21 07:30:22 2001
+++ ./net/if.c	Thu Jun 21 17:56:48 2001
@@ -244,6 +244,13 @@
 	sdl->sdl_len = masklen;
 	while (namelen != 0)
 		sdl->sdl_data[--namelen] = 0xff;
+#ifdef ALTQ
+	ifp->if_snd.altq_type = 0;
+	ifp->if_snd.altq_disc = NULL;
+	ifp->if_snd.altq_flags &= ALTQF_CANTCHANGE;
+	ifp->if_snd.altq_tbr  = NULL;
+	ifp->if_snd.altq_ifp  = ifp;
+#endif
 }
 
 void
@@ -350,6 +357,12 @@
 	if (ifp->if_bpf)
 		bpfdetach(ifp);
 #endif
+#ifdef ALTQ
+	if (ALTQ_IS_ENABLED(&ifp->if_snd))
+		altq_disable(&ifp->if_snd);
+	if (ALTQ_IS_ATTACHED(&ifp->if_snd))
+		altq_detach(&ifp->if_snd);
+#endif
 
 	/*
 	 * Find and remove all routes which is using this interface.
@@ -593,7 +606,7 @@
 	ifp->if_flags &= ~IFF_UP;
 	for (ifa = ifp->if_addrlist.tqh_first; ifa != 0; ifa = ifa->ifa_list.tqe_next)
 		pfctlinput(PRC_IFDOWN, ifa->ifa_addr);
-	if_qflush(&ifp->if_snd);
+	IFQ_PURGE(&ifp->if_snd);
 	rt_ifmsg(ifp);
 
 	/*
diff -urN ../sys/net/if.h ./net/if.h
--- ../sys/net/if.h	Tue Feb  6 21:33:36 2001
+++ ./net/if.h	Thu Jun 21 17:56:48 2001
@@ -37,6 +37,9 @@
  */
 
 #include <sys/queue.h>
+#if 1 /* ALTQ */
+#include <altq/if_altq.h>
+#endif
 
 /*
  * Structures defining a network interface, providing a packet
@@ -102,6 +105,17 @@
 };
 
 /*
+ * Structure defining a queue for a network interface.
+ */
+struct	ifqueue {
+	struct	mbuf *ifq_head;
+	struct	mbuf *ifq_tail;
+	int	ifq_len;
+	int	ifq_maxlen;
+	int	ifq_drops;
+};
+
+/*
  * Values for if_link_state.
  */
 #define	LINK_STATE_UNKNOWN	0	/* link invalid/unknown */
@@ -146,13 +160,11 @@
 		__P((struct ifnet *));
 	void	(*if_watchdog)		/* timer routine */
 		__P((struct ifnet *));
-	struct	ifqueue {
-		struct	mbuf *ifq_head;
-		struct	mbuf *ifq_tail;
-		int	ifq_len;
-		int	ifq_maxlen;
-		int	ifq_drops;
-	} if_snd;			/* output queue */
+#if 1 /* ALTQ */
+	struct	ifaltq if_snd;		/* output queue (includes altq) */
+#else
+	struct	ifqueue if_snd;		/* output queue */
+#endif
 	struct ifprefix *if_prefixlist; /* linked list of prefixes per if */
 };
 #define	if_mtu		if_data.ifi_mtu
@@ -238,6 +250,17 @@
 		(ifq)->ifq_len--; \
 	} \
 }
+#define	IF_POLL(ifq, m)		((m) = (ifq)->ifq_head)
+#define	IF_PURGE(ifq)							\
+while (1) {								\
+	struct mbuf *m0;						\
+	IF_DEQUEUE((ifq), m0);						\
+	if (m0 == NULL)							\
+		break;							\
+	else								\
+		m_freem(m0);						\
+}
+#define	IF_IS_EMPTY(ifq)	((ifq)->ifq_len == 0)
 
 #define	IFQ_MAXLEN	50
 #define	IFNET_SLOWHZ	1		/* granularity is 1 second */
@@ -402,6 +425,107 @@
 	else \
 		(ifa)->ifa_refcnt--; \
 } while (0)
+
+#ifdef ALTQ
+
+#define	IFQ_ENQUEUE(ifq, m, pattr, err)					\
+do {									\
+	if (ALTQ_IS_ENABLED((ifq)))					\
+		ALTQ_ENQUEUE((ifq), (m), (pattr), (err));		\
+	else {								\
+		if (IF_QFULL((ifq))) {					\
+			m_freem((m));					\
+			(err) = ENOBUFS;				\
+		} else {						\
+			IF_ENQUEUE((ifq), (m));				\
+			(err) = 0;					\
+		}							\
+	}								\
+	if ((err))							\
+		(ifq)->ifq_drops++;					\
+} while (0)
+
+#define	IFQ_DEQUEUE(ifq, m)						\
+do {									\
+	if (TBR_IS_ENABLED((ifq)))					\
+		(m) = tbr_dequeue((ifq), ALTDQ_REMOVE);			\
+	else if (ALTQ_IS_ENABLED((ifq)))				\
+		ALTQ_DEQUEUE((ifq), (m));				\
+	else								\
+		IF_DEQUEUE((ifq), (m));					\
+} while (0)
+
+#define	IFQ_POLL(ifq, m)						\
+do {									\
+	if (TBR_IS_ENABLED((ifq)))					\
+		(m) = tbr_dequeue((ifq), ALTDQ_POLL);			\
+	else if (ALTQ_IS_ENABLED((ifq)))				\
+		ALTQ_POLL((ifq), (m));					\
+	else								\
+		IF_POLL((ifq), (m));					\
+} while (0)
+
+#define	IFQ_PURGE(ifq)							\
+do {									\
+	if (ALTQ_IS_ENABLED((ifq)))					\
+		ALTQ_PURGE((ifq));					\
+	else								\
+		IF_PURGE((ifq));					\
+} while (0)
+
+#define	IFQ_SET_READY(ifq)						\
+	do { ((ifq)->altq_flags |= ALTQF_READY); } while (0)
+
+#define	IFQ_CLASSIFY(ifq, m, af, pa)					\
+do {									\
+	if (ALTQ_IS_ENABLED((ifq))) {					\
+		if (ALTQ_NEEDS_CLASSIFY((ifq)))				\
+			(pa)->pattr_class = (*(ifq)->altq_classify)	\
+				((ifq)->altq_clfier, (m), (af));	\
+		(pa)->pattr_af = (af);					\
+		(pa)->pattr_hdr = mtod((m), caddr_t);			\
+	}								\
+} while (0)
+
+#else /* !ALTQ */
+
+#define	IFQ_ENQUEUE(ifq, m, err)					\
+do {									\
+	if (IF_QFULL((ifq))) {						\
+		m_freem((m));						\
+		(err) = ENOBUFS;					\
+	} else {							\
+		IF_ENQUEUE((ifq), (m));					\
+		(err) = 0;						\
+	}								\
+	if ((err))							\
+		(ifq)->ifq_drops++;					\
+} while (0)
+
+#define	IFQ_DEQUEUE(ifq, m)	IF_DEQUEUE((ifq), (m))
+
+#define	IFQ_POLL(ifq, m)	IF_POLL((ifq), (m))
+
+#define	IFQ_PURGE(ifq)							\
+while (1) {								\
+	struct mbuf *m0;						\
+	IF_DEQUEUE((ifq), m0);						\
+	if (m0 == NULL)							\
+		break;							\
+	else								\
+		m_freem(m0);						\
+}
+
+#define	IFQ_SET_READY(ifq)		((void)0)
+#define	IFQ_CLASSIFY(ifq, m, af, pa)	((void)0)
+
+#endif /* !ALTQ */
+
+#define	IFQ_IS_EMPTY(ifq)		((ifq)->ifq_len == 0)
+#define	IFQ_INC_LEN(ifq)		((ifq)->ifq_len++)
+#define	IFQ_DEC_LEN(ifq)		(--(ifq)->ifq_len)
+#define	IFQ_INC_DROPS(ifq)		((ifq)->ifq_drops++)
+#define	IFQ_SET_MAXLEN(ifq, len)	((ifq)->ifq_maxlen = (len))
 
 struct ifnet_head ifnet;
 struct ifnet **ifindex2ifnet;
diff -urN ../sys/net/if_atm.h ./net/if_atm.h
--- ../sys/net/if_atm.h	Mon May 11 03:53:05 1998
+++ ./net/if_atm.h	Thu Jun 21 17:56:48 2001
@@ -42,6 +42,14 @@
 #endif
 #endif /* freebsd doesn't define _KERNEL */
 
+#ifndef NO_ATM_PVCEXT
+/*
+ * ATM_PVCEXT enables PVC extention: VP/VC shaping
+ * and PVC shadow interfaces.
+ */
+#define ATM_PVCEXT	/* enable pvc extention */
+#endif
+
 #if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__)
 #define RTALLOC1(A,B)		rtalloc1((A),(B))
 #elif defined(__FreeBSD__)
@@ -67,6 +75,9 @@
 #define ATM_PH_AAL5    0x01	/* use AAL5? (0 == aal0) */
 #define ATM_PH_LLCSNAP 0x02	/* use the LLC SNAP encoding (iff aal5) */
 
+#ifdef ATM_PVCEXT
+#define ATM_PH_INERNAL  0x20	/* reserve for kernel internal use */
+#endif
 #define ATM_PH_DRIVER7  0x40	/* reserve for driver's use */
 #define ATM_PH_DRIVER8  0x80	/* reserve for driver's use */
 
@@ -85,6 +96,36 @@
 #define SIOCATMENA	_IOWR('a', 123, struct atm_pseudoioctl) /* enable */
 #define SIOCATMDIS	_IOWR('a', 124, struct atm_pseudoioctl) /* disable */
 
+#ifdef ATM_PVCEXT
+
+/* structure to control PVC transmitter */
+struct pvctxreq {
+    /* first entry must be compatible with struct ifreq */
+    char pvc_ifname[IFNAMSIZ];		/* if name, e.g. "en0" */
+    struct atm_pseudohdr pvc_aph;	/* (flags) + vpi:vci */
+    struct atm_pseudohdr pvc_joint;	/* for vp shaping: another vc
+					   to share the shaper */
+    int pvc_pcr;			/* peak cell rate (shaper value) */
+};
+
+/* structure to control PVC bridging */
+struct pvcfwdreq {
+    /* first entry must be compatible with struct ifreq */
+    char pvc_ifname[IFNAMSIZ];		/* if name, e.g. "en0" */
+    char pvc_ifname2[IFNAMSIZ];		/* if name to be bridged to/from */
+    int	 pvc_op;			/* 1:add 0:delete */
+};
+
+/* use ifioctl for now */
+#define SIOCSPVCFWD	_IOW('i', 93, struct pvcfwdreq)
+#define SIOCGPVCFWD	_IOWR('i', 94, struct pvcfwdreq)
+#define SIOCSPVCTX	_IOWR('i', 95, struct pvctxreq)
+#define SIOCGPVCTX	_IOWR('i', 96, struct pvctxreq)
+#define SIOCSPVCSIF	_IOWR('i', 97, struct ifreq)
+#define SIOCGPVCSIF	_IOWR('i', 98, struct ifreq)
+
+#endif /* ATM_PVCEXT */
+
 /*
  * XXX forget all the garbage in if_llc.h and do it the easy way
  */
@@ -109,3 +150,28 @@
 int	atm_output __P((struct ifnet *, struct mbuf *, struct sockaddr *, 
 		struct rtentry *));
 #endif
+#ifdef ATM_PVCEXT
+#ifdef _KERNEL
+#include <sys/queue.h>
+/*
+ * ATM PVC subinterface: a trick to assign a subinterface
+ * to a PVC.
+ * with a pvc subinterface, each PVC looks like an individual
+ * Point-to-Point interface.
+ * as opposed to the NBMA model, a pvc subinterface is inherently
+ * multicast capable (no LANE/MARS required).
+ */
+struct pvcsif {
+	/*
+	 * The ifnet struct _must_ be at the head of this structure.
+	 */
+	struct ifnet sif_if;		/* ifnet structure per pvc */
+	struct atm_pseudohdr sif_aph;	/* flags + vpi:vci */
+	int	sif_vci;		/* vci no */
+	struct ifnet *sif_fwdifp;	/* bridging ifp */
+	LIST_ENTRY(pvcsif) sif_links;
+};
+struct ifnet *pvcsif_alloc __P((void));
+int pvc_set_fwd __P((char *, char *, int));
+#endif
+#endif /* ATM_PVCEXT */
diff -urN ../sys/net/if_atmsubr.c ./net/if_atmsubr.c
--- ../sys/net/if_atmsubr.c	Tue Sep 12 13:09:11 2000
+++ ./net/if_atmsubr.c	Thu Jun 21 17:56:48 2001
@@ -107,17 +107,29 @@
 	struct rtentry *rt0;
 {
 	u_int16_t etype = 0;			/* if using LLC/SNAP */
-	int s, error = 0, sz;
+	int s, error = 0, sz, len;
 	struct atm_pseudohdr atmdst, *ad;
 	register struct mbuf *m = m0;
 	register struct rtentry *rt;
 	struct atmllc *atmllc;
+	struct atmllc *llc_hdr = NULL;
 	u_int32_t atm_flags;
+#ifdef ALTQ
+	struct altq_pktattr pktattr;
+#endif
 
 	if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
 		senderr(ENETDOWN);
 	ifp->if_lastchange = time;
 
+#ifdef ALTQ
+	/*
+	 * if the queueing discipline needs packet classification,
+	 * do it before prepending link headers.
+	 */
+	IFQ_CLASSIFY(&ifp->if_snd, m,
+		     (dst != NULL ? dst->sa_family : AF_UNSPEC), &pktattr);
+#endif
 	/*
 	 * check route
 	 */
@@ -201,6 +213,15 @@
 			type = htons(ETHERTYPE_IPV6);
 			break;
 #endif /* INET6 */
+		case AF_UNSPEC:
+			/*
+			 * XXX: bpfwrite or output from a pvc shadow if.
+			 * assuming dst contains 12 bytes (atm pseudo
+			 * header (4) + LLC/SNAP (8))
+			 */
+			bcopy(dst->sa_data, &atmdst, sizeof(atmdst));
+			llc_hdr = (struct atmllc *)(dst->sa_data + sizeof(atmdst));
+			break;
 
 		default:
 #if defined(__NetBSD__) || defined(__OpenBSD__)
@@ -236,15 +257,18 @@
 	 * Queue message on interface, and start output if interface
 	 * not yet active.
 	 */
-
+	len = m->m_pkthdr.len;
 	s = splimp();
-	if (IF_QFULL(&ifp->if_snd)) {
-		IF_DROP(&ifp->if_snd);
+#ifdef ALTQ
+	IFQ_ENQUEUE(&ifp->if_snd, m, &pktattr, error);
+#else
+	IFQ_ENQUEUE(&ifp->if_snd, m, error);
+#endif
+	if (error) {
 		splx(s);
-		senderr(ENOBUFS);
+		return (error);
 	}
-	ifp->if_obytes += m->m_pkthdr.len;
-	IF_ENQUEUE(&ifp->if_snd, m);
+	ifp->if_obytes += len;
 	if ((ifp->if_flags & IFF_OACTIVE) == 0)
 		(*ifp->if_start)(ifp);
 	splx(s);
@@ -316,6 +340,33 @@
 	    m_adj(m, sizeof(*alc));
 	  }
 
+#ifdef ATM_PVCEXT
+	/* atm bridging support */
+	if ((ifp->if_flags & (IFF_POINTOPOINT|IFF_LINK2)) ==
+		(IFF_POINTOPOINT|IFF_LINK2)) {
+		struct pvcsif *pvcsif = (struct pvcsif *)ifp;
+
+		if (pvcsif->sif_fwdifp != NULL) {
+			struct sockaddr dst;
+
+			/* set address family to dummy dst addr */
+			switch (etype) {
+			case ETHERTYPE_IP:
+				dst.sa_family = AF_INET;
+				break;
+			case ETHERTYPE_IPV6:
+				dst.sa_family = AF_INET6;
+				break;
+			default:
+				m_freem(m);
+				return;
+			}
+			atm_output(pvcsif->sif_fwdifp, m, &dst, NULL);
+			return;
+		}
+	}
+#endif /* ATM_PVCEXT */
+
 	  switch (etype) {
 #ifdef INET
 	  case ETHERTYPE_IP:
@@ -376,4 +427,88 @@
 #endif
 			break;
 		}
+
+}
+
+#ifdef ATM_PVCEXT
+
+static int pvc_max_number = 16;	/* max number of PVCs */
+static int pvc_number = 0;	/* pvc unit number */
+
+struct ifnet *
+pvcsif_alloc()
+{
+	struct pvcsif *pvcsif;
+
+	if (pvc_number >= pvc_max_number)
+		return (NULL);
+	MALLOC(pvcsif, struct pvcsif *, sizeof(struct pvcsif),
+	       M_DEVBUF, M_WAITOK);
+	if (pvcsif == NULL)
+		return (NULL);
+	bzero(pvcsif, sizeof(struct pvcsif));
+
+#if defined(__NetBSD__) || defined (__OpenBSD__)
+	sprintf(pvcsif->sif_if.if_xname, "pvc%d", pvc_number++);
+#else
+	pvcsif->sif_if.if_name = "pvc";
+	pvcsif->sif_if.if_unit = pvc_number++;
+#endif
+	return (&pvcsif->sif_if);
+}
+
+/*
+ * pvc bridging support:
+ * add or delete brigding between 2 pvc interfaces.
+ */
+int
+pvc_set_fwd(if_name, if_name2, op)
+	char *if_name, *if_name2;
+	int op;		/* 0:delete 1:add 2:get */
+{
+	struct ifnet *ifp, *ifp2;
+	struct pvcsif *pvcsif, *pvcsif2;
+
+	if (strncmp(if_name, "pvc", 3) != 0
+	    || (ifp = ifunit(if_name)) == NULL)
+		return (EINVAL);
+	pvcsif = (struct pvcsif *)ifp;
+
+	if (op == 2) {
+		/* get bridging info */
+		if ((ifp2 = pvcsif->sif_fwdifp) == NULL)
+			*if_name2 = '\0';
+		else
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+			sprintf(if_name2, "%s", ifp2->if_xname);
+#else
+			sprintf(if_name2, "%s%d",
+				ifp2->if_name, ifp2->if_unit);
+#endif
+		return (0);
+	}
+
+	if (strncmp(if_name2, "pvc", 3) != 0
+	    || (ifp2 = ifunit(if_name2)) == NULL)
+		return (EINVAL);
+	pvcsif2 = (struct pvcsif *)ifp2;
+
+	if (op) {
+		/* set up bridging */
+		pvcsif->sif_fwdifp = ifp2;
+		pvcsif2->sif_fwdifp = ifp;
+		ifp->if_flags |= IFF_LINK2;	/* use IFF_LINK2 to show */
+		ifp2->if_flags |= IFF_LINK2;	/* bridging is enabled   */
+	}
+	else {
+		/* delete bridging */
+		if (pvcsif->sif_fwdifp != ifp2 || pvcsif2->sif_fwdifp != ifp)
+			return (EINVAL);
+		pvcsif->sif_fwdifp = NULL;
+		pvcsif2->sif_fwdifp = NULL;
+		ifp->if_flags &= ~IFF_LINK2;
+		ifp2->if_flags &= ~IFF_LINK2;
+	}
+	return (0);
 }
+#endif /* ATM_PVCEXT */
diff -urN ../sys/net/if_bridge.c ./net/if_bridge.c
--- ../sys/net/if_bridge.c	Wed Apr  4 05:45:04 2001
+++ ./net/if_bridge.c	Thu Jun 21 18:31:05 2001
@@ -134,6 +134,14 @@
 int	bridge_brlconf __P((struct bridge_softc *, struct ifbrlconf *));
 u_int8_t bridge_filterrule __P((struct brl_head *, struct ether_header *));
 
+#ifdef ALTQ
+/*
+ * ALTQ support in ethernet bridging is only on the enqueue side.
+ */
+static int altq_etherclassify __P((struct ifaltq *, struct mbuf *,
+				   struct altq_pktattr *));
+#endif
+
 #define	ETHERADDR_IS_IP_MCAST(a) \
 	/* struct etheraddr *a;	*/				\
 	((a)->ether_addr_octet[0] == 0x01 &&			\
@@ -741,7 +749,11 @@
 	struct ifnet *dst_if;
 	struct ether_addr *src, *dst;
 	struct bridge_softc *sc;
-	int s;
+	int s, error, len;
+	short mflags;
+#ifdef ALTQ
+	struct altq_pktattr pktattr;
+#endif
 
 	if (m->m_len < sizeof(*eh)) {
 		m = m_pullup(m, sizeof(*eh));
@@ -779,6 +791,9 @@
 			dst_if = p->ifp;
 			if ((dst_if->if_flags & IFF_RUNNING) == 0)
 				continue;
+#ifdef ALTQ
+			if (!ALTQ_IS_ENABLED(&dst_if->if_snd))
+#endif
 			if (IF_QFULL(&dst_if->if_snd)) {
 				IF_DROP(&dst_if->if_snd);
 				sc->sc_if.if_oerrors++;
@@ -794,14 +809,25 @@
 					continue;
 				}
 			}
-
+			len = mc->m_pkthdr.len;
+			mflags = mc->m_flags;
+#ifdef ALTQ
+			if (ALTQ_IS_ENABLED(&dst_if->if_snd))
+				altq_etherclassify(&dst_if->if_snd, mc, &pktattr);
+			IFQ_ENQUEUE(&dst_if->if_snd, mc, &pktattr, error);
+#else
+			IFQ_ENQUEUE(&dst_if->if_snd, mc, error);
+#endif
+			if (error) {
+				sc->sc_if.if_oerrors++;
+				continue;
+			}
 			sc->sc_if.if_opackets++;
-			sc->sc_if.if_obytes += mc->m_pkthdr.len;
+			sc->sc_if.if_obytes += len;
 			dst_if->if_lastchange = time;
-			dst_if->if_obytes += mc->m_pkthdr.len;
-			IF_ENQUEUE(&dst_if->if_snd, mc);
-			if (mc->m_flags & M_MCAST)
-				ifp->if_omcasts++;
+			dst_if->if_obytes += len;
+			if (mflags & M_MCAST)
+				dst_if->if_omcasts++;
 			if ((dst_if->if_flags & IFF_OACTIVE) == 0)
 				(*dst_if->if_start)(dst_if);
 		}
@@ -817,19 +843,25 @@
 		splx(s);
 		return (0);
 	}
-	if (IF_QFULL(&dst_if->if_snd)) {
-		IF_DROP(&dst_if->if_snd);
+	len = m->m_pkthdr.len;
+	mflags = m->m_flags;
+#ifdef ALTQ
+	if (ALTQ_IS_ENABLED(&dst_if->if_snd))
+		altq_etherclassify(&dst_if->if_snd, m, &pktattr);
+	IFQ_ENQUEUE(&dst_if->if_snd, m, &pktattr, error);
+#else
+	IFQ_ENQUEUE(&dst_if->if_snd, m, error);
+#endif
+	if (error) {
 		sc->sc_if.if_oerrors++;
-		m_freem(m);
 		splx(s);
 		return (0);
 	}
 	sc->sc_if.if_opackets++;
-	sc->sc_if.if_obytes += m->m_pkthdr.len;
+	sc->sc_if.if_obytes += len;
 	dst_if->if_lastchange = time;
-	dst_if->if_obytes += m->m_pkthdr.len;
-	IF_ENQUEUE(&dst_if->if_snd, m);
-	if (m->m_flags & M_MCAST)
+	dst_if->if_obytes += len;
+	if (mflags & M_MCAST)
 		dst_if->if_omcasts++;
 	if ((dst_if->if_flags & IFF_OACTIVE) == 0)
 		(*dst_if->if_start)(dst_if);
@@ -877,11 +909,15 @@
 	struct bridge_softc *sc;
 	struct mbuf *m;
 {
-	int s;
+	int s, error, len;
 	struct ifnet *src_if, *dst_if;
 	struct bridge_iflist *ifl;
 	struct ether_addr *dst, *src;
 	struct ether_header eh;
+	short mflags;
+#ifdef ALTQ
+	struct altq_pktattr pktattr;
+#endif
 
 	if ((sc->sc_if.if_flags & IFF_RUNNING) == 0) {
 		m_freem(m);
@@ -1046,20 +1082,28 @@
 		m_freem(m);
 		return;
 	}
+#ifdef ALTQ
+	if (ALTQ_IS_ENABLED(&dst_if->if_snd))
+		altq_etherclassify(&dst_if->if_snd, m, &pktattr);
+#endif
+	len = m->m_pkthdr.len;
+	mflags = m->m_flags;
 	s = splimp();
-	if (IF_QFULL(&dst_if->if_snd)) {
-		IF_DROP(&dst_if->if_snd);
+#ifdef ALTQ
+	IFQ_ENQUEUE(&dst_if->if_snd, m, &pktattr, error);
+#else
+	IFQ_ENQUEUE(&dst_if->if_snd, m, error);
+#endif
+	if (error) {
 		sc->sc_if.if_oerrors++;
-		m_freem(m);
 		splx(s);
 		return;
 	}
 	sc->sc_if.if_opackets++;
-	sc->sc_if.if_obytes += m->m_pkthdr.len;
+	sc->sc_if.if_obytes += len;
 	dst_if->if_lastchange = time;
-	dst_if->if_obytes += m->m_pkthdr.len;
-	IF_ENQUEUE(&dst_if->if_snd, m);
-	if (m->m_flags & M_MCAST)
+	dst_if->if_obytes += len;
+	if (mflags & M_MCAST)
 		dst_if->if_omcasts++;
 	if ((dst_if->if_flags & IFF_OACTIVE) == 0)
 		(*dst_if->if_start)(dst_if);
@@ -1225,7 +1269,11 @@
 	struct bridge_iflist *p;
 	struct mbuf *mc;
 	struct ifnet *dst_if;
-	int used = 0;
+	int error, len, used = 0;
+	short mflags;
+#ifdef ALTQ
+	struct altq_pktattr pktattr;
+#endif
 
 	LIST_FOREACH(p, &sc->sc_iflist, next) {
 		/*
@@ -1248,6 +1296,9 @@
 		if ((dst_if->if_flags & IFF_RUNNING) == 0)
 			continue;
 
+#ifdef ALTQ
+		if (!ALTQ_IS_ENABLED(&dst_if->if_snd))
+#endif
 		if (IF_QFULL(&dst_if->if_snd)) {
 			IF_DROP(&dst_if->if_snd);
 			sc->sc_if.if_oerrors++;
@@ -1275,12 +1326,24 @@
 			continue;
 		}
 
+		len = mc->m_pkthdr.len;
+		mflags = mc->m_flags;
+#ifdef ALTQ
+		if (ALTQ_IS_ENABLED(&dst_if->if_snd))
+			altq_etherclassify(&dst_if->if_snd, mc, &pktattr);
+		IFQ_ENQUEUE(&dst_if->if_snd, mc, &pktattr, error);
+#else
+		IFQ_ENQUEUE(&dst_if->if_snd, mc, error);
+#endif
+		if (error) {
+			sc->sc_if.if_oerrors++;
+			continue;
+		}
 		sc->sc_if.if_opackets++;
-		sc->sc_if.if_obytes += mc->m_pkthdr.len;
-		dst_if->if_obytes += m->m_pkthdr.len;
+		sc->sc_if.if_obytes += len;
+		dst_if->if_obytes += len;
 		dst_if->if_lastchange = time;
-		IF_ENQUEUE(&dst_if->if_snd, mc);
-		if (mc->m_flags & M_MCAST)
+		if (mflags & M_MCAST)
 			dst_if->if_omcasts++;
 		if ((dst_if->if_flags & IFF_OACTIVE) == 0)
 			(*dst_if->if_start)(dst_if);
@@ -1972,3 +2035,80 @@
 	return (NULL);
 }
 #endif
+
+#ifdef ALTQ
+/*
+ * find the size of ethernet header, and call classifier
+ */
+static int
+altq_etherclassify(ifq, m, pktattr)
+	struct ifaltq *ifq;
+	struct mbuf *m;
+	struct altq_pktattr *pktattr;
+{
+	struct ether_header *eh;
+	u_short	ether_type;
+	int	hlen, af, hdrsize;
+	caddr_t hdr;
+
+	hlen = sizeof(struct ether_header);
+	eh = mtod(m, struct ether_header *);
+
+	ether_type = ntohs(eh->ether_type);
+	if (ether_type < ETHERMTU) {
+		/* ick! LLC/SNAP */
+		struct llc *llc = (struct llc *)(eh + 1);
+		hlen += 8;
+
+		if (m->m_len < hlen ||
+		    llc->llc_dsap != LLC_SNAP_LSAP ||
+		    llc->llc_ssap != LLC_SNAP_LSAP ||
+		    llc->llc_control != LLC_UI)
+			goto bad;  /* not snap! */
+
+		ether_type = ntohs(llc->llc_un.type_snap.ether_type);
+	}
+
+	if (ether_type == ETHERTYPE_IP) {
+		af = AF_INET;
+		hdrsize = 20;  /* sizeof(struct ip) */
+#ifdef INET6
+	} else if (ether_type == ETHERTYPE_IPV6) {
+		af = AF_INET6;
+		hdrsize = 40;  /* sizeof(struct ip6_hdr) */
+#endif
+	} else
+		goto bad;
+
+	while (m->m_len <= hlen) {
+		hlen -= m->m_len;
+		m = m->m_next;
+	}
+	hdr = m->m_data + hlen;
+	if (m->m_len < hlen + hdrsize) {
+		/*
+		 * ip header is not in a single mbuf.  this should not
+		 * happen in the current code.
+		 * (todo: use m_pulldown in the future)
+		 */
+		goto bad;
+	}
+	m->m_data += hlen;
+	m->m_len -= hlen;
+	if (ALTQ_NEEDS_CLASSIFY(ifq))
+		pktattr->pattr_class =
+		    (*ifq->altq_classify)(ifq->altq_clfier, m, af);
+	m->m_data -= hlen;
+	m->m_len += hlen;
+
+	pktattr->pattr_af = af;
+	pktattr->pattr_hdr = hdr;
+	return (1);
+
+bad:
+	pktattr->pattr_class = NULL;
+	pktattr->pattr_hdr = NULL;
+	pktattr->pattr_af = AF_UNSPEC;
+	return (0);
+}
+#endif /* ALTQ */
diff -urN ../sys/net/if_ethersubr.c ./net/if_ethersubr.c
--- ../sys/net/if_ethersubr.c	Wed Apr  4 05:45:04 2001
+++ ./net/if_ethersubr.c	Thu Jun 21 17:56:49 2001
@@ -245,13 +245,17 @@
 	struct rtentry *rt0;
 {
 	u_int16_t etype;
-	int s, error = 0;
+	int s, len, error = 0;
  	u_char edst[6];
 	register struct mbuf *m = m0;
 	register struct rtentry *rt;
 	struct mbuf *mcopy = (struct mbuf *)0;
 	register struct ether_header *eh;
 	struct arpcom *ac = (struct arpcom *)ifp;
+	short mflags;
+#ifdef ALTQ
+	struct altq_pktattr pktattr;
+#endif
 
 	if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
 		senderr(ENETDOWN);
@@ -278,6 +282,13 @@
 			    time.tv_sec < rt->rt_rmx.rmx_expire)
 				senderr(rt == rt0 ? EHOSTDOWN : EHOSTUNREACH);
 	}
+#ifdef ALTQ
+	/*
+	 * if the queueing discipline needs packet classification,
+	 * do it before prepending link headers.
+	 */
+	IFQ_CLASSIFY(&ifp->if_snd, m, dst->sa_family, &pktattr);
+#endif
 	switch (dst->sa_family) {
 
 #ifdef INET
@@ -519,19 +530,25 @@
 	}
 #endif
 
+	mflags = m->m_flags;
+	len = m->m_pkthdr.len;
 	s = splimp();
 	/*
 	 * Queue message on interface, and start output if interface
 	 * not yet active.
 	 */
-	if (IF_QFULL(&ifp->if_snd)) {
-		IF_DROP(&ifp->if_snd);
+#ifdef ALTQ
+	IFQ_ENQUEUE(&ifp->if_snd, m, &pktattr, error);
+#else
+	IFQ_ENQUEUE(&ifp->if_snd, m, error);
+#endif
+	if (error) {
+		/* mbuf is already freed */
 		splx(s);
-		senderr(ENOBUFS);
+		return (error);
 	}
-	ifp->if_obytes += m->m_pkthdr.len;
-	IF_ENQUEUE(&ifp->if_snd, m);
-	if (m->m_flags & M_MCAST)
+	ifp->if_obytes += len + sizeof (struct ether_header);
+	if (mflags & M_MCAST)
 		ifp->if_omcasts++;
 	if ((ifp->if_flags & IFF_OACTIVE) == 0)
 		(*ifp->if_start)(ifp);
diff -urN ../sys/net/if_loop.c ./net/if_loop.c
--- ../sys/net/if_loop.c	Tue Feb  6 21:33:36 2001
+++ ./net/if_loop.c	Thu Jun 21 18:33:16 2001
@@ -145,6 +145,10 @@
 #define	LOMTU	(32768 +  MHLEN + MLEN)
 #endif
   
+#ifdef ALTQ
+static void lo_altqstart __P((struct ifnet *));
+#endif
+
 void
 loopattach(n)
 	int n;
@@ -168,6 +172,10 @@
 		ifp->if_type = IFT_LOOP;
 		ifp->if_hdrlen = sizeof(u_int32_t);
 		ifp->if_addrlen = 0;
+		IFQ_SET_READY(&ifp->if_snd);
+#ifdef ALTQ
+		ifp->if_start = lo_altqstart;
+#endif
 		if_attachhead(ifp);
 #if NBPFILTER > 0
 		bpfattach(&ifp->if_bpf, ifp, DLT_LOOP, sizeof(u_int32_t));
@@ -222,6 +230,37 @@
 
 	ifp->if_opackets++;
 	ifp->if_obytes += m->m_pkthdr.len;
+#ifdef ALTQ
+	/*
+	 * altq for loop is just for debugging.
+	 * only used when called for loop interface (not for
+	 * a simplex interface).
+	 */
+	if ((ALTQ_IS_ENABLED(&ifp->if_snd) || TBR_IS_ENABLED(&ifp->if_snd))
+	    && ifp->if_start == lo_altqstart) {
+		struct altq_pktattr pktattr;
+		int32_t *afp;
+	        int error;
+
+		/*
+		 * if the queueing discipline needs packet classification,
+		 * do it before prepending link headers.
+		 */
+		IFQ_CLASSIFY(&ifp->if_snd, m, dst->sa_family, &pktattr);
+
+		M_PREPEND(m, sizeof(int32_t), M_DONTWAIT);
+		if (m == 0)
+			return(ENOBUFS);
+		afp = mtod(m, int32_t *);
+		*afp = (int32_t)dst->sa_family;
+
+	        s = splimp();
+		IFQ_ENQUEUE(&ifp->if_snd, m, &pktattr, error);
+		(*ifp->if_start)(ifp);
+		splx(s);
+		return (error);
+	}
+#endif /* ALTQ */
 	switch (dst->sa_family) {
 
 #ifdef INET
@@ -280,6 +319,87 @@
 	splx(s);
 	return (0);
 }
+
+#ifdef ALTQ
+static void
+lo_altqstart(ifp)
+	struct ifnet *ifp;
+{
+	struct ifqueue *ifq;
+	struct mbuf *m;
+	int32_t af, *afp;
+	int s, isr;
+	
+	while (1) {
+		s = splimp();
+		IFQ_DEQUEUE(&ifp->if_snd, m);
+		splx(s);
+		if (m == NULL)
+			return;
+
+		afp = mtod(m, int32_t *);
+		af = *afp;
+		m_adj(m, sizeof(int32_t));
+
+		switch (af) {
+#ifdef INET
+		case AF_INET:
+			ifq = &ipintrq;
+			isr = NETISR_IP;
+			break;
+#endif
+#ifdef INET6
+		case AF_INET6:
+			m->m_flags |= M_LOOP;
+			ifq = &ip6intrq;
+			isr = NETISR_IPV6;
+			break;
+#endif
+#ifdef IPX
+		case AF_IPX:
+			ifq = &ipxintrq;
+			isr = NETISR_IPX;
+			break;
+#endif
+#ifdef NS
+		case AF_NS:
+			ifq = &nsintrq;
+			isr = NETISR_NS;
+			break;
+#endif
+#ifdef ISO
+		case AF_ISO:
+			ifq = &clnlintrq;
+			isr = NETISR_ISO;
+			break;
+#endif
+#ifdef NETATALK
+		case AF_APPLETALK:
+			ifq = &atintrq2;
+			isr = NETISR_ATALK;
+			break;
+#endif NETATALK
+		default:
+			printf("lo_altqstart: can't handle af%d\n", af);
+			m_freem(m);
+			return;
+		}
+
+		s = splimp();
+		if (IF_QFULL(ifq)) {
+			IF_DROP(ifq);
+			m_freem(m);
+			splx(s);
+			return;
+		}
+		IF_ENQUEUE(ifq, m);
+		schednetisr(isr);
+		ifp->if_ipackets++;
+		ifp->if_ibytes += m->m_pkthdr.len;
+		splx(s);
+	}
+}
+#endif /* ALTQ */
 
 /* ARGSUSED */
 void
diff -urN ../sys/net/if_ppp.c ./net/if_ppp.c
--- ../sys/net/if_ppp.c	Wed Mar 22 08:31:27 2000
+++ ./net/if_ppp.c	Thu Jun 21 17:56:49 2001
@@ -199,10 +199,11 @@
 	sc->sc_if.if_hdrlen = PPP_HDRLEN;
 	sc->sc_if.if_ioctl = pppsioctl;
 	sc->sc_if.if_output = pppoutput;
-	sc->sc_if.if_snd.ifq_maxlen = IFQ_MAXLEN;
+	IFQ_SET_MAXLEN(&sc->sc_if.if_snd, IFQ_MAXLEN);
 	sc->sc_inq.ifq_maxlen = IFQ_MAXLEN;
 	sc->sc_fastq.ifq_maxlen = IFQ_MAXLEN;
 	sc->sc_rawq.ifq_maxlen = IFQ_MAXLEN;
+	IFQ_SET_READY(&sc->sc_if.if_snd);
 	if_attach(&sc->sc_if);
 #if NBPFILTER > 0
 	bpfattach(&sc->sc_bpf, &sc->sc_if, DLT_PPP, PPP_HDRLEN);
@@ -639,6 +640,9 @@
     enum NPmode mode;
     int len;
     struct mbuf *m;
+#ifdef ALTQ
+    struct altq_pktattr pktattr;
+#endif
 
     if (sc->sc_devp == NULL || (ifp->if_flags & IFF_RUNNING) == 0
 	|| ((ifp->if_flags & IFF_UP) == 0 && dst->sa_family != AF_UNSPEC)) {
@@ -646,6 +650,9 @@
 	goto bad;
     }
 
+#ifdef ALTQ
+    IFQ_CLASSIFY(&ifp->if_snd, m0, dst->sa_family, &pktattr);
+#endif
     /*
      * Compute PPP header.
      */
@@ -762,16 +769,34 @@
 	m0->m_nextpkt = NULL;
 	sc->sc_npqtail = &m0->m_nextpkt;
     } else {
-	ifq = (m0->m_flags & M_HIGHPRI)? &sc->sc_fastq: &ifp->if_snd;
-	if (IF_QFULL(ifq) && dst->sa_family != AF_UNSPEC) {
-	    IF_DROP(ifq);
+	if ((m0->m_flags & M_HIGHPRI)
+#ifdef ALTQ
+	    && !ALTQ_IS_ENABLED(&sc->sc_if.if_snd)
+#endif
+	    ) {
+	    ifq = &sc->sc_fastq;
+	    if (IF_QFULL(ifq) && dst->sa_family != AF_UNSPEC) {
+		IF_DROP(ifq);
+		m_freem(m0);
+		error = ENOBUFS;
+	    }
+	    else {
+		IF_ENQUEUE(ifq, m0);
+		error = 0;
+	    }
+	} else {
+#ifdef ALTQ
+	    IFQ_ENQUEUE(&sc->sc_if.if_snd, m0, &pktattr, error);
+#else
+	    IFQ_ENQUEUE(&sc->sc_if.if_snd, m0, error);
+#endif
+	}
+	if (error) {
 	    splx(s);
 	    sc->sc_if.if_oerrors++;
 	    sc->sc_stats.ppp_oerrors++;
-	    error = ENOBUFS;
-	    goto bad;
+	    return (error);
 	}
-	IF_ENQUEUE(ifq, m0);
 	(*sc->sc_start)(sc);
     }
     ifp->if_lastchange = time;
@@ -798,6 +823,7 @@
     struct mbuf *m, **mpp;
     struct ifqueue *ifq;
     enum NPmode mode;
+    int error;
 
     for (mpp = &sc->sc_npqueue; (m = *mpp) != NULL; ) {
 	switch (PPP_PROTOCOL(mtod(m, u_char *))) {
@@ -815,13 +841,32 @@
 	     */
 	    *mpp = m->m_nextpkt;
 	    m->m_nextpkt = NULL;
-	    ifq = (m->m_flags & M_HIGHPRI)? &sc->sc_fastq: &sc->sc_if.if_snd;
-	    if (IF_QFULL(ifq)) {
-		IF_DROP(ifq);
+	    if ((m->m_flags & M_HIGHPRI)
+#ifdef ALTQ
+		&& !ALTQ_IS_ENABLED(&sc->sc_if.if_snd)
+#endif
+		) {
+		ifq = &sc->sc_fastq;
+		if (IF_QFULL(ifq)) {
+		    IF_DROP(ifq);
+		    m_freem(m);
+		    error = ENOBUFS;
+		}
+		else {
+		    IF_ENQUEUE(ifq, m);
+		    error = 0;
+		}
+	    } else {
+#ifdef ALTQ
+		IFQ_ENQUEUE(&sc->sc_if.if_snd, m, NULL, error);
+#else
+		IFQ_ENQUEUE(&sc->sc_if.if_snd, m, error);
+#endif
+	    }
+	    if (error) {
 		sc->sc_if.if_oerrors++;
 		sc->sc_stats.ppp_oerrors++;
-	    } else
-		IF_ENQUEUE(ifq, m);
+	    }
 	    break;
 
 	case NPMODE_DROP:
@@ -873,7 +918,7 @@
      */
     IF_DEQUEUE(&sc->sc_fastq, m);
     if (m == NULL)
-	IF_DEQUEUE(&sc->sc_if.if_snd, m);
+	IFQ_DEQUEUE(&sc->sc_if.if_snd, m);
     if (m == NULL)
       return NULL;
 
@@ -999,7 +1044,7 @@
     s = splsoftnet();
     for (i = 0; i < NPPP; ++i, ++sc) {
 	if (!(sc->sc_flags & SC_TBUSY)
-	    && (sc->sc_if.if_snd.ifq_head || sc->sc_fastq.ifq_head)) {
+	    && (!IFQ_IS_EMPTY(&sc->sc_if.if_snd) || sc->sc_fastq.ifq_head)) {
 	    s2 = splimp();
 	    sc->sc_flags |= SC_TBUSY;
 	    splx(s2);
diff -urN ../sys/net/if_sl.c ./net/if_sl.c
--- ../sys/net/if_sl.c	Wed Mar 14 06:30:27 2001
+++ ./net/if_sl.c	Thu Jun 21 17:56:49 2001
@@ -214,8 +214,9 @@
 		sc->sc_if.if_type = IFT_SLIP;
 		sc->sc_if.if_ioctl = slioctl;
 		sc->sc_if.if_output = sloutput;
-		sc->sc_if.if_snd.ifq_maxlen = 50;
+		IFQ_SET_MAXLEN(&sc->sc_if.if_snd, 50);
 		sc->sc_fastq.ifq_maxlen = 32;
+		IFQ_SET_READY(&sc->sc_if.if_snd);
 		if_attach(&sc->sc_if);
 #if NBPFILTER > 0
 		bpfattach(&sc->sc_bpf, &sc->sc_if, DLT_SLIP, SLIP_HDRLEN);
@@ -380,8 +381,14 @@
 	register struct sl_softc *sc = ifp->if_softc;
 	register struct ip *ip;
 	register struct ifqueue *ifq;
-	int s;
+	int s, error;
+#ifdef ALTQ
+	struct altq_pktattr pktattr;
+#endif
 
+#ifdef ALTQ
+	IFQ_CLASSIFY(&ifp->if_snd, m, dst->sa_family, &pktattr);
+#endif
 	/*
 	 * `Cannot happen' (see slioctl).  Someday we will extend
 	 * the line protocol to support other address families.
@@ -403,14 +410,11 @@
 		m_freem(m);
 		return (EHOSTUNREACH);
 	}
-	ifq = &sc->sc_if.if_snd;
 	ip = mtod(m, struct ip *);
 	if (sc->sc_if.if_flags & SC_NOICMP && ip->ip_p == IPPROTO_ICMP) {
 		m_freem(m);
 		return (ENETRESET);		/* XXX ? */
 	}
-	if (ip->ip_tos & IPTOS_LOWDELAY)
-		ifq = &sc->sc_fastq;
 	s = splimp();
 	if (sc->sc_oqlen && sc->sc_ttyp->t_outq.c_cc == sc->sc_oqlen) {
 		struct timeval tv;
@@ -422,14 +426,33 @@
 			slstart(sc->sc_ttyp);
 		}
 	}
-	if (IF_QFULL(ifq)) {
-		IF_DROP(ifq);
-		m_freem(m);
+	if ((ip->ip_tos & IPTOS_LOWDELAY)
+#ifdef ALTQ
+	    && !ALTQ_IS_ENABLED(&sc->sc_if.if_snd)
+#endif
+		) {
+		ifq = &sc->sc_fastq;
+		if (IF_QFULL(ifq)) {
+			IF_DROP(ifq);
+			m_freem(m);
+			error = ENOBUFS;
+		} else {
+			IF_ENQUEUE(ifq, m);
+			error = 0;
+		}
+	} else {
+#ifdef ALTQ
+		IFQ_ENQUEUE(&sc->sc_if.if_snd, m, &pktattr, error);
+#else
+		IFQ_ENQUEUE(&sc->sc_if.if_snd, m, error);
+#endif
+	}
+	if (error) {
 		splx(s);
 		sc->sc_if.if_oerrors++;
-		return (ENOBUFS);
+		return (error);
 	}
-	IF_ENQUEUE(ifq, m);
+
 	sc->sc_if.if_lastchange = time;
 	if ((sc->sc_oqlen = sc->sc_ttyp->t_outq.c_cc) == 0)
 		slstart(sc->sc_ttyp);
@@ -496,7 +519,7 @@
 		if (m)
 			sc->sc_if.if_omcasts++;		/* XXX */
 		else
-			IF_DEQUEUE(&sc->sc_if.if_snd, m);
+			IFQ_DEQUEUE(&sc->sc_if.if_snd, m);
 		splx(s);
 		if (m == NULL)
 			return;
diff -urN ../sys/net/if_spppsubr.c ./net/if_spppsubr.c
--- ../sys/net/if_spppsubr.c	Wed Apr  4 05:45:04 2001
+++ ./net/if_spppsubr.c	Thu Jun 21 17:56:49 2001
@@ -639,8 +639,11 @@
 {
 	struct sppp *sp = (struct sppp*) ifp;
 	struct ppp_header *h;
-	struct ifqueue *ifq;
-	int s, rv = 0;
+	struct ifqueue *ifq = NULL;
+	int s, len, rv = 0;
+#ifdef ALTQ
+	struct altq_pktattr pktattr;
+#endif
 
 	s = splimp();
 
@@ -662,7 +665,13 @@
 		s = splimp();
 	}
 
-	ifq = &ifp->if_snd;
+#ifdef ALTQ
+	/*
+	 * if the queueing discipline needs packet classification,
+	 * do it before prepending link headers.
+	 */
+	IFQ_CLASSIFY(&ifp->if_snd, m, dst->sa_family, &pktattr);
+#endif
 #ifdef INET
 	/*
 	 * Put low delay, telnet, rlogin and ftp control packets
@@ -782,14 +791,33 @@
 	 * Queue message on interface, and start output if interface
 	 * not yet active.
 	 */
-	if (IF_QFULL (ifq)) {
-		IF_DROP (&ifp->if_snd);
-		m_freem (m);
+	len = m->m_pkthdr.len;
+	if (ifq != NULL
+#ifdef ALTQ
+	    && !ALTQ_IS_ENABLED(&ifp->if_snd)
+#endif
+		) {
+		if (IF_QFULL (ifq)) {
+			IF_DROP (&ifp->if_snd);
+			m_freem (m);
+			if (rv == 0)
+				rv = ENOBUFS;
+		}
+		IF_ENQUEUE (ifq, m);
+	}
+	else {
+#ifdef ALTQ
+		IFQ_ENQUEUE(&ifp->if_snd, m, &pktattr, rv);
+#else
+		IFQ_ENQUEUE(&ifp->if_snd, m, rv);
+#endif
+	}
+	if (rv != 0) {
 		++ifp->if_oerrors;
 		splx (s);
-		return (rv? rv: ENOBUFS);
+		return (rv);
 	}
-	IF_ENQUEUE (ifq, m);
+
 	if (! (ifp->if_flags & IFF_OACTIVE))
 		(*ifp->if_start) (ifp);
 
@@ -798,7 +826,7 @@
 	 * The packet length includes header, FCS and 1 flag,
 	 * according to RFC 1333.
 	 */
-	ifp->if_obytes += m->m_pkthdr.len + 3;
+	ifp->if_obytes += len + 3;
 	splx (s);
 	return (0);
 }
@@ -823,7 +851,7 @@
 
 	sp->pp_if.if_type = IFT_PPP;
 	sp->pp_if.if_output = sppp_output;
-	sp->pp_if.if_snd.ifq_maxlen = 50;
+	IFQ_SET_MAXLEN(&sp->pp_if.if_snd, 50);
 	sp->pp_fastq.ifq_maxlen = 50;
 	sp->pp_cpq.ifq_maxlen = 50;
 	sp->pp_loopcnt = 0;
@@ -870,7 +898,7 @@
 {
 	struct sppp *sp = (struct sppp*) ifp;
 
-	sppp_qflush (&sp->pp_if.if_snd);
+	IFQ_PURGE(&sp->pp_if.if_snd);
 	sppp_qflush (&sp->pp_fastq);
 	sppp_qflush (&sp->pp_cpq);
 }
@@ -886,7 +914,7 @@
 
 	s = splimp();
 	empty = !sp->pp_fastq.ifq_head && !sp->pp_cpq.ifq_head &&
-		!sp->pp_if.if_snd.ifq_head;
+		IFQ_IS_EMPTY(&sp->pp_if.if_snd);
 	splx(s);
 	return (empty);
 }
@@ -913,7 +941,7 @@
 	    (sppp_ncp_check(sp) || (sp->pp_flags & PP_CISCO) != 0)) {
 		IF_DEQUEUE(&sp->pp_fastq, m);
 		if (m == NULL)
-			IF_DEQUEUE (&sp->pp_if.if_snd, m);
+			IFQ_DEQUEUE (&sp->pp_if.if_snd, m);
 	}
 	splx(s);
 	return m;
@@ -936,7 +964,7 @@
 	    (sp->pp_phase == PHASE_NETWORK ||
 	     (sp->pp_flags & PP_CISCO) != 0))
 		if ((m = sp->pp_fastq.ifq_head) == NULL)
-			m = sp->pp_if.if_snd.ifq_head;
+			IFQ_POLL(&sp->pp_if.if_snd, m);
 	splx (s);
 	return (m);
 }
diff -urN ../sys/net/if_strip.c ./net/if_strip.c
--- ../sys/net/if_strip.c	Fri Jan 19 12:38:14 2001
+++ ./net/if_strip.c	Thu Jun 21 17:56:49 2001
@@ -362,11 +362,12 @@
 		sc->sc_if.if_type = IFT_SLIP;
 		sc->sc_if.if_ioctl = stripioctl;
 		sc->sc_if.if_output = stripoutput;
-		sc->sc_if.if_snd.ifq_maxlen = 50;
+		IFQ_SET_MAXLEN(&sc->sc_if.if_snd, 50);
 		sc->sc_fastq.ifq_maxlen = 32;
 
 		sc->sc_if.if_watchdog = strip_watchdog;
 		sc->sc_if.if_timer = STRIP_WATCHDOG_INTERVAL;
+		IFQ_SET_READY(&sc->sc_if.if_snd);
 		if_attach(&sc->sc_if);
 #if NBPFILTER > 0
 		bpfattach(&sc->sc_bpf, &sc->sc_if, DLT_SLIP, SLIP_HDRLEN);
@@ -715,7 +716,9 @@
 	register u_char *dldst;		/* link-level next-hop */
 	int s;
 	u_char dl_addrbuf[STARMODE_ADDR_LEN+1];
-
+#ifdef ALTQ
+	struct altq_pktattr pktattr;
+#endif
 
 	/*
 	 * Verify tty line is up and alive.
@@ -779,13 +782,17 @@
 		return (EAFNOSUPPORT);
 	}
 	
-	ifq = &sc->sc_if.if_snd;
+	ifq = NULL;
 	ip = mtod(m, struct ip *);
 	if (sc->sc_if.if_flags & SC_NOICMP && ip->ip_p == IPPROTO_ICMP) {
 		m_freem(m);
 		return (ENETRESET);		/* XXX ? */
 	}
-	if (ip->ip_tos & IPTOS_LOWDELAY)
+	if ((ip->ip_tos & IPTOS_LOWDELAY)
+#ifdef ALTQ
+	    && !ALTQ_IS_ENABLED(&sc->sc_if.if_snd)
+#endif
+		)
 		ifq = &sc->sc_fastq;
 
 	/*
@@ -843,14 +850,27 @@
 			stripstart(sc->sc_ttyp);
 		}
 	}
-	if (IF_QFULL(ifq)) {
-		IF_DROP(ifq);
-		m_freem(m);
+	if (ifq != NULL) {
+		if (IF_QFULL(ifq)) {
+			IF_DROP(ifq);
+			m_freem(m);
+			error = ENOBUFS;
+		} else {
+			IF_ENQUEUE(ifq, m);
+			error = 0;
+		}
+	} else {
+#ifdef ALTQ
+		IFQ_ENQUEUE(&sc->sc_if.if_snd, m, &pktattr, error);
+#else
+		IFQ_ENQUEUE(&sc->sc_if.if_snd, m, error);
+#endif
+	}
+	if (error) {
 		splx(s);
 		sc->sc_if.if_oerrors++;
-		return (ENOBUFS);
+		return (error);
 	}
-	IF_ENQUEUE(ifq, m);
 	sc->sc_if.if_lastchange = time;
 	if ((sc->sc_oqlen = sc->sc_ttyp->t_outq.c_cc) == 0) {
 		stripstart(sc->sc_ttyp);
@@ -940,7 +960,7 @@
 		if (m)
 			sc->sc_if.if_omcasts++;		/* XXX */
 		else
-			IF_DEQUEUE(&sc->sc_if.if_snd, m);
+			IFQ_DEQUEUE(&sc->sc_if.if_snd, m);
 		splx(s);
 		if (m == NULL) {
 			return;
diff -urN ../sys/netinet/ip_input.c ./netinet/ip_input.c
--- ../sys/netinet/ip_input.c	Wed Apr  4 05:45:06 2001
+++ ./netinet/ip_input.c	Thu Jun 21 17:56:49 2001
@@ -366,6 +366,12 @@
 		goto bad;
 	}
 
+#ifdef ALTQ
+	if (altq_input != NULL && (*altq_input)(m, AF_INET) == 0)
+		/* packet is dropped by traffic conditioner */
+		return;
+#endif
+
 	/*
 	 * Convert fields to host representation.
 	 */
diff -urN ../sys/netinet6/ip6_input.c ./netinet6/ip6_input.c
--- ../sys/netinet6/ip6_input.c	Wed Apr  4 05:45:07 2001
+++ ./netinet6/ip6_input.c	Thu Jun 21 18:38:39 2001
@@ -277,6 +277,13 @@
 
 	ip6stat.ip6s_nxthist[ip6->ip6_nxt]++;
 
+#ifdef ALTQ
+	if (altq_input != NULL && (*altq_input)(m, AF_INET6) == 0) {
+		/* packet is dropped by traffic conditioner */
+		return;
+	}
+#endif
+
 	/*
 	 * Scope check
 	 */
