Subject: port-vax/2796: vax if_qe lacks multicast, bpf +FIX
To: None <gnats-bugs@gnats.netbsd.org>
From: Jonathan Stone <jonathan@DSG.Stanford.EDU>
List: netbsd-bugs
Date: 10/02/1996 03:37:59
>Number:         2796
>Category:       port-vax
>Synopsis:       vax if_qe lacks multicast, bpf +FIX
>Confidential:   no
>Severity:       critical
>Priority:       high
>Responsible:    gnats-admin (GNATS administrator)
>State:          open
>Class:          change-request
>Submitter-Id:   net
>Arrival-Date:   Wed Oct  2 03:50:01 1996
>Last-Modified:
>Originator:     Jonathan Stone
>Organization:
	Stanford DSG
>Release:        1.2
>Environment:
	
System: NetBSD Cup.DSG.Stanford.EDU 1.2_BETA NetBSD 1.2_BETA (DSG) #47: Mon Jul 29 12:05:57 PDT 1996 jonathan@Cup.DSG.Stanford.EDU:/aga/n1/src/NetBSD/IP-PLUS/src/sys/arch/i386/compile/DSG i386

this problem report has _nothing_ to do with the above machine

>Description:

The vax qe (and de) drivers lack multicast support.
They also lack bpf support.

>How-To-Repeat:

Try any BPF-based application
Try running tcpdump on NetBSD/vax.

Try using NetBSD/vax as a MOP server.


Try the LBL tools, or any other IP multicast app
	(e.g., pinging the 224.0.0.1 address).
	Watch NetBSD/vax not respond.

>Fix:

The following patch for if_qe.c is untested, but probably
basically correct. Similar patches worked on -Tahoe and -reno.
It could do with a compile  with -Wall -Wstrict-rpototypes,
and review of the multicast-filter update code.


Note that i have added BFP hooks into the qe driver
rather than into the if_uba support code deliberately;
the if_uba code cannot  do the the bpfattach(),
so I think the bpf wiretaps should be duplicated here
and in if_de.c.


NetBSD doesn't really support IFF_ALMULTI; the support
for adding more than 16 multicast filters probably needs
work. As noted, the ISO support in 4.4-Lite is broken,
and needs reworking to coexist with IPmulticast.
Calling up the stack to ether_addmulti(), instead of inling
ISO addresses, is probably the right thing to do.

Better support for DELQA native "turbo" mode is possible
and should be implemented.


Index: if_qe.c
===================================================================
RCS file: /cvsroot/src/sys/arch/vax/if/if_qe.c,v
retrieving revision 1.16
diff -c -r1.16 if_qe.c
*** if_qe.c	1996/08/20 14:07:42	1.16
--- if_qe.c	1996/10/02 10:24:50
***************
*** 136,142 ****
--- 136,146 ----
  
  /*
   * Digital Q-BUS to NI Adapter
+  * supports DEQNA and DELQA in DEQNA-mode.
   */
+ 
+ #include "bpfilter.h"
+ 
  #include <sys/param.h>
  #include <sys/systm.h>
  #include <sys/mbuf.h>
***************
*** 173,181 ****
  extern char all_es_snpa[], all_is_snpa[], all_l1is_snpa[], all_l2is_snpa[];
  #endif
  
  #include <machine/pte.h>
  #include <machine/cpu.h>
! #include <machine/mtpr.h>
  
  #include <vax/if/if_qereg.h>
  #include <vax/if/if_uba.h>
--- 177,198 ----
  extern char all_es_snpa[], all_is_snpa[], all_l1is_snpa[], all_l2is_snpa[];
  #endif
  
+ #if defined(CCITT) && defined(LLC)
+ #include <sys/socketvar.h>
+ #include <netccitt/x25.h>
+ #include <netccitt/pk.h>
+ #include <netccitt/pk_var.h>
+ #include <netccitt/pk_extern.h>
+ #endif
+ 
+ #if NBPFILTER > 0
+ #include <net/bpf.h>
+ #include <net/bpfdesc.h>
+ #endif
+ 
  #include <machine/pte.h>
  #include <machine/cpu.h>
! #include <machine/mtpr.h>		/* XXX Qbus mips?  */
  
  #include <vax/if/if_qereg.h>
  #include <vax/if/if_uba.h>
***************
*** 224,229 ****
--- 241,247 ----
  	int	qe_intvec;		/* Interrupt vector 		*/
  	struct	qedevice *addr; /* device addr		*/
  	int 	setupqueued;		/* setup packet queued		*/
+ 	int	setuplength;		/* length of setup packet       */
  	int	nxmit;			/* Transmits in progress	*/
  	int	qe_restarts;		/* timeouts			*/
  };
***************
*** 369,375 ****
  	 * The Deqna is cable of transmitting broadcasts, but
  	 * doesn't listen to its own.
  	 */
! 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS;
  
  	/*
  	 * Read the address from the prom and save it.
--- 387,394 ----
  	 * The Deqna is cable of transmitting broadcasts, but
  	 * doesn't listen to its own.
  	 */
! 	ifp->if_flags = IFF_BROADCAST | IFF_MULTICAST |IFF_SIMPLEX | 
! 		IFF_NOTRAILERS;
  
  	/*
  	 * Read the address from the prom and save it.
***************
*** 394,399 ****
--- 413,424 ----
  	sc->qe_uba.iff_flags = UBA_CANTWAIT;
  	if_attach(ifp);
  	ether_ifattach(ifp);
+ 
+ #if NBPFILTER > 0
+ 	bpfattach(&ifp->if_bpf, ifp, DLT_EN10MB, sizeof(struct ether_header));
+ #endif
+ 
+ 
  }
  
  /*
***************
*** 540,546 ****
  		rp = &sc->tring[index];
  		if( sc->setupqueued ) {
  			buf_addr = sc->setupaddr;
! 			len = 128;
  			rp->qe_setup = 1;
  			sc->setupqueued = 0;
  		} else {
--- 565,571 ----
  		rp = &sc->tring[index];
  		if( sc->setupqueued ) {
  			buf_addr = sc->setupaddr;
! 			len = sc->setuplength;
  			rp->qe_setup = 1;
  			sc->setupqueued = 0;
  		} else {
***************
*** 549,554 ****
--- 574,583 ----
  				splx(s);
  				return;
  			}
+ #if NBPFILTER > 0
+ 			if (ifp->if_bpf)
+ 				bpf_mtap(ifp->if_bpf, m);
+ #endif
  			buf_addr = sc->qe_ifw[index].ifw_info;
  			len = if_ubaput(&sc->qe_uba, &sc->qe_ifw[index], m);
  		}
***************
*** 768,773 ****
--- 797,803 ----
  {
  	struct qe_softc *sc = ifp->if_softc;
  	struct ifaddr *ifa = (struct ifaddr *)data;
+ 	struct ifreq *ifr = (struct ifreq *)data;
  	int s = splnet(), error = 0;
  
  	switch (cmd) {
***************
*** 804,809 ****
--- 834,863 ----
  		} else if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) ==
  		    IFF_RUNNING && (sc->qe_flags & QEF_RUNNING) == 0)
  			qerestart(sc);
+ 		else
+ 			/*
+ 			 * In case IFF_PROMISC or IFF_ALLMULTI has changed.
+ 			 */
+ 			qesetup(sc);
+ 		break;
+ 
+ 	case SIOCADDMULTI:
+ 	case SIOCDELMULTI:
+ 		/*
+ 		 * Update our multicast list.
+ 		 */
+ 		error = (cmd == SIOCADDMULTI) ?
+ 			ether_addmulti(ifr, &sc->qe_ac):
+ 			ether_delmulti(ifr, &sc->qe_ac);
+ 
+ 		if (error == ENETRESET) {
+ 			/*
+ 			 * Multicast list has changed; set the hardware filter
+ 			 * accordingly.
+ 			 */
+ 			qesetup(sc);			
+ 			error = 0;
+ 		}
  		break;
  
  	default:
***************
*** 878,890 ****
--- 932,989 ----
  	 */
  	for (i = 0; i < 6; i++) {
  		sc->setup_pkt[i][2] = 0xff;
+ 
+ 
  #ifdef ISO
+ 		/*
+ 		 * XXX layer violation, should use SIOCADDMULTI.
+ 		 * Will definitely break with IPmulticast.
+ 		 */
  		sc->setup_pkt[i][3] = all_es_snpa[i];
  		sc->setup_pkt[i][4] = all_is_snpa[i];
  		sc->setup_pkt[i][5] = all_l1is_snpa[i];
  		sc->setup_pkt[i][6] = all_l2is_snpa[i];
  #endif
  	}
+ 	if (sc->qe_if.if_flags & IFF_PROMISC) {
+ 		sc->setuplength = QE_PROMISC;
+ 	}
+ 	/* XXX no IFF_ALLMULTI support in 4.4bsd */
+ 	else if (sc->qe_if.if_flags & IFF_ALLMULTI) {
+ 		sc->setuplength = QE_ALLMULTI;
+ 	}
+ 	else {
+ 		register k;
+ 		struct ether_multi *enm;
+ 		struct ether_multistep step;
+ 		/*
+ 		 * Step through our list of multicast addresses, putting them
+ 		 * in the third through fourteenth address slots of the setup
+ 		 * packet.  (See the DEQNA manual to understand the peculiar
+ 		 * layout of the bytes within the setup packet.)  If we have
+ 		 * too many multicast addresses, or if we have to listen to
+ 		 * a range of multicast addresses, turn on reception of all
+ 		 * multicasts.
+ 		 */
+ 		sc->setuplength = QE_SOMEMULTI;
+ 		i = 2;
+ 		k = 0;
+ 		ETHER_FIRST_MULTI(step, &sc->qe_ac, enm);
+ 		while (enm != NULL) {
+ 			if ((++i > 7 && k != 0) ||
+ 			    bcmp(enm->enm_addrlo, enm->enm_addrhi, 6) != 0) {
+ 				sc->setuplength = QE_ALLMULTI;
+ 				break;
+ 			}
+ 			if (i > 7) {
+ 				i = 1;
+ 				k = 8;
+ 			}
+ 			for (j = 0; j < 6; j++)
+ 				sc->setup_pkt[j+k][i] = enm->enm_addrlo[j];
+ 			ETHER_NEXT_MULTI(step, enm);
+ 		}
+ 	}
  	sc->setupqueued++;
  }
  
***************
*** 911,916 ****
--- 1010,1016 ----
  	if (len == 0)
  		return;
  
+ 
  	/*
  	 * Pull packet off interface.  Off is nonzero if packet
  	 * has trailing header; qeget will then force this header
***************
*** 924,930 ****
  *(((u_long *)m->m_data)+1),
  *(((u_long *)m->m_data)+2),
  *(((u_long *)m->m_data)+3)
! ); }
  #endif
  
  	if (m)
--- 1024,1053 ----
  *(((u_long *)m->m_data)+1),
  *(((u_long *)m->m_data)+2),
  *(((u_long *)m->m_data)+3)
! ; }
! #endif
! 
! #if NBPFILTER > 0
! 	/*
! 	 * Check if there's a BPF listener on this interface.
! 	 * If so, hand off the raw packet to BPF.
! 	 */
! 	if (ifp->if_bpf) {
! 		bpf_mtap(ifp->if_bpf, m);
! 
! 		/*
! 		 * Note that the interface cannot be in promiscuous mode if
! 		 * there are no BPF listeners.  And if we are in promiscuous
! 		 * mode, we have to check if this packet is really ours.
! 		 */
! 		if ((ifp->if_flags & IFF_PROMISC) &&
! 		    (eh->ether_dhost[0] & 1) == 0 && /* !mcast and !bcast */
! 		    bcmp(eh->ether_dhost, sc->qe_arpcom.ac_enaddr,
! 			    sizeof(eh->ether_dhost)) != 0) {
! 			m_freem(m);
! 			return;
! 		}
! 	}
  #endif
  
  	if (m)
Index: if_qereg.h
===================================================================
RCS file: /cvsroot/src/sys/arch/vax/if/if_qereg.h,v
retrieving revision 1.1
diff -c -r1.1 if_qereg.h
*** if_qereg.h	1995/03/30 20:26:41	1.1
--- if_qereg.h	1996/10/02 10:24:51
***************
*** 170,172 ****
--- 170,179 ----
  #define QE_NOTYET		0x8000	/* Descriptor not in use yet	*/
  #define QE_INUSE		0x4000	/* Descriptor being used by QNA	*/
  #define QE_MASK			0xc000	/* Lastnot/error/used mask	*/
+ 
+ /*
+  * Values for the length of the setup packet that control reception filter.
+  */
+ #define QE_SOMEMULTI		128	/* Receive up to 12 multicasts  */
+ #define QE_ALLMULTI		129	/* Receive all multicasts       */
+ #define QE_PROMISC		130	/* Receive all packets          */
>Audit-Trail:
>Unformatted: