Subject: kern/1250: BPF writes confuse fe driver
To: None <gnats-bugs@NetBSD.ORG>
From: John Hawkinson <jhawk@MIT.EDU>
List: netbsd-bugs
Date: 07/21/1995 04:05:34
>Number:         1250
>Category:       kern
>Synopsis:       BPF writes confuse fe driver
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    kern-bug-people (Kernel Bug People)
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Fri Jul 21 04:20:01 1995
>Last-Modified:
>Originator:     John Hawkinson
>Organization:
MIT SIPB
>Release:        -current of 1 July 1995
>Environment:
System: NetBSD lola-granola 1.0A NetBSD 1.0A (LOLA) #61: Sat Jul 15 17:47:47 EDT 1995 jhawk@lola-granola:/afs/sipb.mit.edu/project/netbsd/dev/current-source/build/i386_nbsd1/sys/arch/i386/compile/LOLA i386


>Description:

	If I feed a raw ethernet packet to the bpf device that's attached
	to fe0 (Fujitsu Ethernet driver, AT1700 card), the driver gets
	confused and interprets the last two bytes of the destination
	ethernet address as the packet size.

	This machine has two ethernet interfaces, ed0 and fe0. These
	problems happen on fe0, but the same code works fine on ed0,
	so I assume the driver is to blame.

	Additionally, I decided to test this on lo0 as a control.
	This resulted in a panic with "looutput no HDR", presumbably
	my punishment for handing the loopback interface an ethernet
	header. Is this a bug (a userspace process causing the kernel
	to panic), or is that to be expected when you screw up dealing
	with the kernel at such a low level (bpf)?

>How-To-Repeat:

	Attached is a stripped-down version of a hacked-up program
	I was working on at the time (No, it's not supposed to be
	an example of good coding style, but it gets the job done).

	When "iface" is set to "ed0", "tcpdump -e -i ed0 -x" produces:

03:43:21.382410 2:60:8c:a9:f7:ae 0:0:c:5:a2:33 ip 36: truncated-ip - 18 bytes missing![|tcp]
			 4500 0028 1234 0000 1e06 0000 1246 0019
			 1246 00e4 4100


	And the program produces:

buffer is 4096.
>From 08:00:20:75:6c:8a to 00:00:0c:05:a2:33
Packet length is 36.

	However, when "iface" is set to "fe0", tcpdump produces no
	output and the following is syslogged:

Jul 21 02:14:32 lola-granola /netbsd: fe0: got a big packet (13218 bytes) to send
Jul 21 02:14:33 lola-granola /netbsd: fe0: device timeout

	Note that the fe driver claims the packet is 13218 bytes long,
	which is 0x33a2, which are the last two bytes of the destination
	ethernet address.

	I've looked at both net/bpf.c and dev/isa/if_{fe,ed}.c, and I'm
	not really sure where the problem is, or how to go about
	debugging it. Any help'd be appreciated.

---cut
#include <stdio.h>
#include <ctype.h>
#include <errno.h>

#include <sys/param.h>
#include <sys/time.h>
#include <sys/timeb.h>
#include <sys/socket.h>
#include <sys/file.h>
#include <sys/ioctl.h>

#include <net/bpf.h>
#include <net/if.h>
#include <netinet/in_systm.h>
#include <netinet/in.h>
#include <netinet/if_ether.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>

#include <string.h>

int main() {
  int fd;
  int n = 0;
  char device [sizeof "/dev/bpf000"];
  char iface[] = "ed0";
  char packet[1000]; int plen; char *p;
  struct ifreq ifr;
  struct bpf_version bv;
	      
	      
  /* liberally stolen from libpcap: */
     
   /*
    * Go through all the minors and find one that isn't in use.
    */
  do {
	(void)sprintf(device, "/dev/bpf%d", n++);
	fd = open(device, O_WRONLY);
  } while (fd < 0 && errno == EBUSY);
  
  if (fd < 0) {
	fprintf(stderr, "%s: %s\n", device, strerror(errno));
	return 1;
  }
  
  strcpy(ifr.ifr_name, iface);
  if (ioctl(fd, BIOCSETIF, (caddr_t)&ifr) < 0) {
    fprintf(stderr, "%s: %s\n", device, strerror(errno));
    return 1;
  }
  
  if (ioctl(fd, BIOCGBLEN, (caddr_t)&n) < 0) {
    errx("BIOCGBLEN");
  } else {
    printf("buffer is %d.\n", n);
  }

  /* Build packet here! */

  {
    struct ether_addr esrc, edst;
    struct ether_header ehead;
    struct ip iphead;
    struct tcphdr thead;

    p=packet;

    bcopy((char*)ether_aton("8:0:20:75:6c:8a"), &ehead.ether_shost,
	  sizeof(struct ether_addr));	/* should be granola */
    bcopy((char*)ether_aton("0:0:c:5:a2:33"), &ehead.ether_dhost,
	  sizeof(struct ether_addr));	/* w20rtr */
    ehead.ether_type = htons(ETHERTYPE_IP);
    fprintf(stdout, "From %s", ether_ntoa(ehead.ether_shost));
    fprintf(stdout, " to %s\n", ether_ntoa(ehead.ether_dhost));
    bcopy(&ehead, p, sizeof(ehead)); p+=sizeof(ehead);

/* IP */

    iphead.ip_hl=5;
    iphead.ip_v=4;
    iphead.ip_tos=0;
    iphead.ip_len=htons(54-14);	/* XXX */
    iphead.ip_id= htons(0x1234);
    iphead.ip_off=0;
    iphead.ip_ttl= 30;
    iphead.ip_p = IPPROTO_TCP;
    iphead.ip_sum = 0; /* XXX */
    if (inet_aton("18.70.0.228", &iphead.ip_dst) < 0)
      err("dst");
    if (inet_aton("18.70.0.25", &iphead.ip_src) < 0)
      err("src");

    bcopy(&iphead, p, sizeof(iphead)); p+=sizeof(iphead);

    *p++='A';
    *p++=0;

    plen=p-packet;
    printf("Packet length is %d.\n", plen);
  }

  if (write(fd, packet, plen) < 0) {
    fprintf(stderr, "write failed (%d): %s\n", errno, strerror(errno));
    return 1;
  }

  close(fd);

  return 0;
}

---cut


>Fix:

>Audit-Trail:
>Unformatted: