Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 24 Oct 1996 16:40:13 +0600 (ESD)
From:      "Serge A. Babkin" <babkin@hq.icb.chel.su>
To:        hackers@freebsd.org, jkh@time.cdrom.com, asami@freebsd.org, wollman@frebsd.org.hq.icb.chel.su
Subject:   Networking in PCEMU (1/2)
Message-ID:  <199610241040.QAA08864@hq.icb.chel.su>

next in thread | raw e-mail | index | archive | help
Hi!

I wrote the code that allows to access the network from pcemu.
It is also a great debugging environment in case you have
no real network. Commit it please. The first part contains
the kernel part (Garrett, please take a look at it) and the second
part contains the patch for pcemu (Satoshi, please take a look
a it). I plan to use it to port the Netware emulator from
Linux some day (may be not very soon).

Thank you!

-SB

Part 1:


*** /sys/net/if_loe.c	Thu Oct 24 19:36:17 1996
--- /sys/net/if_loe.c	Thu Oct 24 15:02:41 1996
***************
*** 0 ****
--- 1,755 ----
+ /*
+  * Copyright (c) 1996
+  *	Serge A. Babkin.  All rights reserved.
+  *
+  * Redistribution and use in source and binary forms, with or without
+  * modification, are permitted provided that the following conditions
+  * are met:
+  * 1. Redistributions of source code must retain the above copyright
+  *    notice, this list of conditions and the following disclaimer.
+  * 2. Redistributions in binary form must reproduce the above copyright
+  *    notice, this list of conditions and the following disclaimer in the
+  *    documentation and/or other materials provided with the distribution.
+  *
+  *
+  * Loopback Ethernet-simulating interface
+  *
+  */
+ 
+ #include "loe.h"
+ #if NLOE > 0
+ 
+ #include "bpfilter.h"
+ 
+ #include <sys/param.h>
+ #if defined(__FreeBSD__)
+ #include <sys/systm.h>
+ #include <sys/kernel.h>
+ #include <sys/conf.h>
+ #include <sys/devconf.h>
+ #endif
+ #include <sys/mbuf.h>
+ #include <sys/socket.h>
+ #include <sys/ioctl.h>
+ #include <sys/errno.h>
+ #include <sys/syslog.h>
+ #include <sys/proc.h>
+ #include <sys/fcntl.h>
+ #if defined(__NetBSD__)
+ #include <sys/select.h>
+ #endif
+ 
+ #include <net/if.h>
+ #include <net/if_dl.h>
+ #include <net/if_types.h>
+ 
+ #ifdef INET
+ #include <netinet/in.h>
+ #include <netinet/in_systm.h>
+ #include <netinet/in_var.h>
+ #include <netinet/ip.h>
+ #include <netinet/if_ether.h>
+ #endif
+ 
+ #ifdef IPX
+ #include <netipx/ipx.h>
+ #include <netipx/ipx_if.h>
+ #endif
+ 
+ #ifdef NS
+ #include <netns/ns.h>
+ #include <netns/ns_if.h>
+ #endif
+ 
+ #if NBPFILTER > 0
+ #include <net/bpf.h>
+ #include <net/bpfdesc.h>
+ #endif
+ 
+ #if defined(__FreeBSD__)
+ #include <machine/clock.h>
+ #endif
+ 
+ #ifdef DEVFS
+ #include <sys/devfsext.h>
+ #endif
+ 
+ /* Exported variables */
+ u_long	loe_unit;
+ 
+ static	int loeioctl __P((struct ifnet * ifp, int, caddr_t));
+ static	void loestart __P((struct ifnet *ifp));
+ static	void loeread __P((struct ifnet *ifp, struct mbuf *m));
+ 
+ static char driver_name[]="loe";
+ 
+ static d_open_t loecopen;
+ static d_close_t loecclose;
+ static d_read_t loecread;
+ static d_write_t loecwrite;
+ static d_select_t loecselect;
+ static d_ioctl_t loecioctl;
+ 
+ #define CDEV_MAJOR 77
+ static struct cdevsw loe_cdevsw = {
+ 	loecopen, loecclose, loecread, loecwrite,
+ 	loecioctl, nullstop, noreset, nodevtotty,
+ 	loecselect, nommap, NULL, driver_name,
+ 	NULL, -1
+ };
+ 
+ static	void loeattach __P((void *));
+ PSEUDO_SET(loeattach, if_loe);
+ 
+ struct arpcom loearp[NLOE];
+ 
+ struct loeinfo {
+ 	struct ifqueue q; /* read queue */
+ 	struct selinfo si;
+ 	char isopen; /* open flag */
+ 	char wantread;
+ 	char wantselect;
+ 	char fionbio;
+ 	};
+ 
+ static struct loeinfo loeinfo[NLOE];
+ 
+ #define ETHER_ADDR_LEN 6
+ #define ETHER_MAX_LEN 1518
+ 
+ static void
+ loeattach(dummy)
+ 	void *dummy;
+ {
+     struct ifaddr *ifa;
+     struct ifnet *ifp;
+     struct sockaddr_dl *sdl;
+     u_short *p;
+     int i;
+ 	static char ethaddr[ETHER_ADDR_LEN]={0,0,0,0,0,0};
+ 	dev_t dev;
+ 
+ 	for(i=0; i<NLOE; i++) {
+ 		printf("loe%d: loopback Ethernet\n",i);
+ 		ifp = &loearp[i].ac_if;
+ 
+ 		ifp->if_softc = &loearp[i];
+ 		ifp->if_unit = i;
+ 		ifp->if_name = "loe";
+ 		ifp->if_mtu = ETHERMTU;
+ 		ifp->if_flags = IFF_BROADCAST | IFF_MULTICAST | IFF_RUNNING ;
+ 		ifp->if_output = ether_output;
+ 		ifp->if_start = loestart;
+ 		ifp->if_ioctl = loeioctl;
+ 		ifp->if_watchdog = 0;
+ 
+ 		if_attach(ifp);
+ 		ether_ifattach(ifp);
+ 
+ 		/* fill the arpcom Ethernet address */
+ 		ethaddr[5]=i+1; 
+ 		bcopy(ethaddr, &loearp[i].ac_enaddr, ETHER_ADDR_LEN);
+ 
+ 		/*
+ 		 * Fill the hardware address into ifa_addr if we find an AF_LINK entry.
+ 		 * We need to do this so bpf's can get the hardware addr of this card.
+ 		 * netstat likes this too!
+ 		 */
+ 		ifa = ifp->if_addrlist;
+ 		while ((ifa != 0) && (ifa->ifa_addr != 0) &&
+ 		   (ifa->ifa_addr->sa_family != AF_LINK))
+ 				ifa = ifa->ifa_next;
+ 
+ 		if ((ifa != 0) && (ifa->ifa_addr != 0)) {
+ 			sdl = (struct sockaddr_dl *) ifa->ifa_addr;
+ 			sdl->sdl_type = IFT_ETHER;
+ 			sdl->sdl_alen = ETHER_ADDR_LEN;
+ 			sdl->sdl_slen = 0;
+ 			bcopy(ethaddr, LLADDR(sdl), ETHER_ADDR_LEN);
+ 		}
+ 
+ #if NBPFILTER > 0
+ 		bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header));
+ #endif
+ 
+ 		dev=makedev(CDEV_MAJOR,0);
+ 		cdevsw_add(&dev, &loe_cdevsw, NULL);
+ #ifdef DEVFS
+ 		devfs_add_devswf(&sio_cdevsw, i, DV_CHR, UID_ROOT, GID_WHEEL, 0666,
+ 			"loe%d",i);
+ #endif
+ 
+ 		loeinfo[i].isopen=0;
+ 		loeinfo[i].wantread=0;
+ 		loeinfo[i].wantselect=0;
+ 		loeinfo[i].fionbio=0;
+ 		loeinfo[i].q.ifq_head=NULL;
+ 		loeinfo[i].q.ifq_tail=NULL;
+ 		loeinfo[i].q.ifq_len=0;
+ 		loeinfo[i].q.ifq_maxlen=IFQ_MAXLEN;
+ 		loeinfo[i].q.ifq_drops=0;
+ 	}
+ }
+ 
+ static void
+ loestart(ifp)
+     struct ifnet *ifp;
+ {
+     register struct mbuf *m;
+ 	struct ether_header *eh;
+ 	int unit = (struct arpcom *)ifp->if_softc - loearp;
+ 	int i;
+ 	int s;
+ 
+ 	s=splimp();
+ 
+     /* Sneak a peek at the next packet */
+     m = ifp->if_snd.ifq_head;
+     if (m == 0) {
+ 		splx(s);
+ 		return;
+     }
+ 
+ 	IF_DEQUEUE(&ifp->if_snd, m);
+ 	eh = mtod(m, struct ether_header *);
+ 
+ 	if(eh->ether_dhost[0] & 1) { /* broadcast or multicast,
+ 									Ethernet has reverse bit order */
+ 		if(ifp->if_flags & IFF_DEBUG) {
+ 			printf("loe%d: multicast %x:%x:%x:%x:%x:%x ->", unit, 
+ 				eh->ether_shost[0],
+ 				eh->ether_shost[1],
+ 				eh->ether_shost[2],
+ 				eh->ether_shost[3],
+ 				eh->ether_shost[4],
+ 				eh->ether_shost[5]);
+ 			printf("%x:%x:%x:%x:%x:%x\n", 
+ 				eh->ether_dhost[0],
+ 				eh->ether_dhost[1],
+ 				eh->ether_dhost[2],
+ 				eh->ether_dhost[3],
+ 				eh->ether_dhost[4],
+ 				eh->ether_dhost[5]);
+ 		}
+ 
+ 		for(i=0; i<NLOE; i++)
+ 			loeread(&loearp[i].ac_if, m);
+ 	} else { /* unicast */
+ 		if(ifp->if_flags & IFF_DEBUG) {
+ 			printf("loe%d: unicast %x:%x:%x:%x:%x:%x ->", unit, 
+ 				eh->ether_shost[0],
+ 				eh->ether_shost[1],
+ 				eh->ether_shost[2],
+ 				eh->ether_shost[3],
+ 				eh->ether_shost[4],
+ 				eh->ether_shost[5]);
+ 			printf("%x:%x:%x:%x:%x:%x [%d]\n", 
+ 				eh->ether_dhost[0],
+ 				eh->ether_dhost[1],
+ 				eh->ether_dhost[2],
+ 				eh->ether_dhost[3],
+ 				eh->ether_dhost[4],
+ 				eh->ether_dhost[5],
+ 				eh->ether_dhost[5]-1);
+ 		}
+ 
+ 		if(eh->ether_dhost[5]>0 && eh->ether_dhost[5]<=NLOE) { /* our address */
+ 			loeread(&loearp[eh->ether_dhost[5]-1].ac_if, m);
+ 		}
+ 		/* honor the promiscuous interfaces */
+ 		for(i=0; i<NLOE; i++) {
+ 			if(loearp[i].ac_if.if_flags & IFF_PROMISC &&
+ 				i!=eh->ether_dhost[5]-1)
+ 					loeread(&loearp[i].ac_if, m);
+ 		}
+ 	}
+ 
+ 	m_freem(m);
+ 	splx(s);
+ }
+ 
+ static void
+ loeread(ifp,m)
+ 	struct ifnet *ifp;
+ 	struct mbuf *m;
+ {
+ 	struct mbuf *n, *c;
+ 	struct mbuf *n2;
+     struct ether_header *eh;
+ 	int len;
+ 	int unit = (struct arpcom *)ifp->if_softc - loearp;
+ 
+ 	if(ifp->if_flags & IFF_DEBUG) {
+ 		printf("loe%d: receiving a packet, isopen=%d\n",unit,
+ 			loeinfo[unit].isopen);
+ 	}
+ 
+ 	n=m_copypacket(m,M_WAIT);
+ 
+ 	if(n==0)
+ 		return;
+ 
+ 	eh = mtod(n, struct ether_header *);
+ 
+     ++ifp->if_ipackets;
+     n->m_pkthdr.rcvif = ifp;
+ 
+ 	/* compute the length */
+ 	for(len=0, c=n; c!=0; c=c->m_next)
+ 		len += c->m_len;
+ 
+     n->m_pkthdr.len = len;
+ 
+ #if NBPFILTER > 0
+     if (ifp->if_bpf) {
+ 		bpf_mtap(ifp, n);
+ 	}
+ #endif
+ 
+ 	/* remove link-layer address */
+ 
+ 	n->m_pkthdr.len -= sizeof(struct ether_header);
+ 	n->m_len -= sizeof(struct ether_header);
+ 	n->m_data += sizeof(struct ether_header);
+ 
+     ether_input(ifp, eh, n);
+ 
+ 	if(loeinfo[unit].isopen) {
+ 		if(IF_QFULL(&loeinfo[unit].q))
+ 			return;
+ 		n2=m_copypacket(m,M_WAIT);
+ 		if(n2==0)
+ 			return;
+ 
+ 		IF_ENQUEUE(&loeinfo[unit].q, n2);
+ 		if(ifp->if_flags & IFF_DEBUG) {
+ 			printf("loe%d: enqueued a packet\n",unit);
+ 		}
+ 
+ 		if(loeinfo[unit].wantread) {
+ 			if(ifp->if_flags & IFF_DEBUG) {
+ 				printf("loe%d: woke up a reader\n",unit);
+ 			}
+ 			loeinfo[unit].wantread=0;
+ 			wakeup(&loeinfo[unit].wantread);
+ 		}
+ 		if(loeinfo[unit].wantselect) {
+ 			if(ifp->if_flags & IFF_DEBUG) {
+ 				printf("loe%d: woke up a select\n",unit);
+ 			}
+ 			loeinfo[unit].wantselect=0;
+ 			selwakeup(&loeinfo[unit].si);
+ 		}
+ 	}
+ }
+ 
+ /*
+  * Look familiar?
+  */
+ static int
+ loeioctl(ifp, cmd, data)
+     register struct ifnet *ifp;
+     int cmd;
+     caddr_t data;
+ {
+     register struct ifaddr *ifa = (struct ifaddr *) data;
+     struct ifreq *ifr = (struct ifreq *) data;
+     int s, error = 0;
+ 	int unit = ifp->if_unit;
+ 	struct arpcom *ac=ifp->if_softc;
+ 
+     switch (cmd) {
+       case SIOCSIFADDR:
+ 		ifp->if_flags |= IFF_UP;
+ 
+ 		switch (ifa->ifa_addr->sa_family) {
+ #ifdef INET
+ 		  case AF_INET:
+ 			if(ifp->if_flags & IFF_DEBUG)
+ 				printf("loe%d: ioctl SIOCSIFADDR INET\n",unit);
+ 
+ 			arp_ifinit((struct arpcom *)ifp, ifa);
+ 			break;
+ #endif
+ #ifdef IPX
+ 		  case AF_IPX:
+ 			{
+ 			register struct ipx_addr *ina = &(IA_SIPX(ifa)->sipx_addr);
+ 
+ 			if(ifp->if_flags & IFF_DEBUG)
+ 				printf("loe%d: ioctl SIOCSIFADDR IPX\n",unit);
+ 
+ 			if (ipx_nullhost(*ina))
+ 				ina->x_host =
+ 				*(union ipx_host *) (ac->ac_enaddr);
+ 			else {
+ 				bcopy((caddr_t) ina->x_host.c_host,
+ 				  (caddr_t) ac->ac_enaddr,
+ 				  sizeof(ac->ac_enaddr));
+ 			}
+ 			break;
+ 			}
+ #endif
+ #ifdef NS
+ 		  case AF_NS:
+ 			{
+ 			register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
+ 
+ 			if(ifp->if_flags & IFF_DEBUG)
+ 				printf("loe%d: ioctl SIOCSIFADDR NS\n",unit);
+ 
+ 			if (ns_nullhost(*ina))
+ 				ina->x_host =
+ 				*(union ns_host *) (ac->ac_enaddr);
+ 			else {
+ 				bcopy((caddr_t) ina->x_host.c_host,
+ 				  (caddr_t) ac->ac_enaddr,
+ 				  sizeof(ac->ac_enaddr));
+ 			}
+ 			break;
+ 			}
+ #endif
+ 		  default:
+ 			if(ifp->if_flags & IFF_DEBUG)
+ 				printf("loe%d: ioctl SIOCSIFADDR 0x%x\n",unit,
+ 					ifa->ifa_addr->sa_family);
+ 
+ 			break;
+ 		}
+ 		break;
+ 	  case SIOCGIFADDR:
+ 		{ 
+ 		  struct sockaddr *sa; 
+ 	 
+ 		  if(ifp->if_flags & IFF_DEBUG)
+ 			printf("loe%d: ioctl SIOCGIFADDR\n",unit);
+ 
+ 		  sa = (struct sockaddr *) & ifr->ifr_data;
+ 		  bcopy((caddr_t) ac->ac_enaddr, 
+ 			(caddr_t) sa->sa_data, ETHER_ADDR_LEN);
+ 		}
+ 		break;
+       case SIOCSIFFLAGS:
+ 		if(ifp->if_flags & IFF_DEBUG)
+ 			printf("loe%d: ioctl SIOCSIFFLAGS\n",unit);
+ 
+ 		break;
+ #ifdef notdef
+       case SIOCGHWADDR:
+ 		if(ifp->if_flags & IFF_DEBUG)
+ 			printf("loe%d: ioctl SIOCGHWADDR\n",unit);
+ 
+ 		bcopy((caddr_t) sc->sc_addr, (caddr_t) & ifr->ifr_data,
+ 			  sizeof(sc->sc_addr));
+ 		break;
+ #endif
+ 	case SIOCSIFMTU:
+ 
+ 		if(ifp->if_flags & IFF_DEBUG)
+ 			printf("loe%d: ioctl SIOCSIFMTU\n",unit);
+ 
+ 		/*
+ 		 * Set the interface MTU.
+ 		 */
+ 		if (ifr->ifr_mtu > ETHERMTU) {
+ 			error = EINVAL;
+ 		} else {
+ 			ifp->if_mtu = ifr->ifr_mtu;
+ 		}
+ 		break; 
+ 	case SIOCADDMULTI:
+ 	case SIOCDELMULTI:
+ 	    /* Now this driver has no support for programmable
+ 	     * multicast filters. If some day it will gain this
+ 	     * support this part of code must be extended.
+ 	     */
+ 		if(ifp->if_flags & IFF_DEBUG)
+ 			printf("loe%d: ioctl ADD/DELMULTI\n",unit);
+ 
+ 	    error=0;
+ 	    break;
+       default:
+ 		if(ifp->if_flags & IFF_DEBUG)
+ 			printf("loe%d: ioctl 0x%x\n",unit,cmd);
+ 
+ 		error = EINVAL;
+     }
+ 
+     return (error);
+ }
+ 
+ static int 
+ loecopen(dev, flag, mode, p)
+ 	dev_t dev;
+ 	int flag;
+ 	int mode;
+ 	struct proc *p;
+ {
+ 	int mynor=minor(dev);
+     struct ifnet *ifp;
+ 
+ 	ifp = &loearp[mynor].ac_if;
+ 
+ 	if(mynor<NLOE) {
+ 		loeinfo[mynor].isopen=1;
+ 		if(ifp->if_flags & IFF_DEBUG) {
+ 			printf("loe%d: open, isopen=%d\n",mynor, loeinfo[mynor].isopen);
+ 		}
+ 		return 0;
+ 	} else {
+ 		return ENODEV;
+ 	}
+ }
+ 
+ static int 
+ loecclose(dev, flag, mode, p)
+ 	dev_t dev;
+ 	int flag;
+ 	int mode;
+ 	struct proc *p;
+ {
+ 	struct mbuf *m;
+ 	int mynor=minor(dev);
+     struct ifnet *ifp;
+ 	int s;
+ 
+ 	ifp = &loearp[mynor].ac_if;
+ 
+ 	if(mynor<NLOE) {
+ 		loeinfo[mynor].isopen=0;
+ 
+ 		s=splimp();
+ 		while( loeinfo[mynor].q.ifq_head!=0 ) {
+ 			IF_DEQUEUE(&loeinfo[mynor].q, m);
+ 			m_freem(m);
+ 		}
+ 		splx(s);
+ 
+ 		if(ifp->if_flags & IFF_DEBUG) {
+ 			printf("loe%d: close, isopen=%d\n",mynor, loeinfo[mynor].isopen);
+ 		}
+ 		return 0;
+ 	} else {
+ 		return ENODEV;
+ 	}
+ }
+ 
+ static int 
+ loecread(dev, uio, flag)
+ 	dev_t dev;
+ 	struct uio *uio;
+ 	int flag;
+ {
+ 	struct mbuf *m, *n;
+ 	int mynor=minor(dev);
+ 	int s;
+ 	int error;
+     struct ifnet *ifp;
+ 
+ 	ifp = &loearp[mynor].ac_if;
+ 
+ #if 0
+ 	if(ifp->if_flags & IFF_DEBUG) {
+ 		printf("loe%d: read, isopen=%d\n",mynor, loeinfo[mynor].isopen);
+ 	}
+ #endif
+ 
+ 	if(uio->uio_resid < ETHER_MAX_LEN)
+ 		return ENOSPC;
+ 
+ 	s=splimp();
+ 	while( loeinfo[mynor].q.ifq_head==0 ) {
+ 		if(loeinfo[mynor].fionbio) {
+ 			splx(s);
+ 			return EAGAIN;
+ 		}
+ 		if(ifp->if_flags & IFF_DEBUG) {
+ 			printf("loe%d: sleeping on read\n",mynor);
+ 		}
+ 		loeinfo[mynor].wantread=1;
+ 		error=tsleep(&loeinfo[mynor].wantread, (PZERO+1)|PCATCH, "loecread", 0);
+ 		if(error) {
+ 			splx(s);
+ 			return EINTR;
+ 		}
+ 	}
+ 
+ 	IF_DEQUEUE(&loeinfo[mynor].q, m);
+ 
+ 	for(n=m, error=0; n!=0 && n->m_len!=0 && !error; n=n->m_next) {
+ 		error=uiomove(mtod(n, char *), n->m_len, uio);
+ 	}
+ 
+ 	if(error) {
+ 		/* return mbuf back */
+ 		IF_PREPEND(&loeinfo[mynor].q, m);
+ 
+ 		if(ifp->if_flags & IFF_DEBUG) {
+ 			printf("loe%d: error %d during reading %d bytes\n",mynor,
+ 				error, m->m_pkthdr.len);
+ 		}
+ 		splx(s);
+ 		return error;
+ 	}
+ #if 0
+ 	if(ifp->if_flags & IFF_DEBUG) {
+ 		int c;
+ 		struct mbuf *mb;
+ 
+ 		for(mb=mmbfree, c=0 ; mb!=0; mb=mb->m_next)
+ 			c++;
+ 		printf("loe%d: before freeing: %d mbufs free\n",mynor,
+ 			c);
+ 		for(mb=m, c=0 ; mb!=0; mb=mb->m_next)
+ 			c++;
+ 		printf("loe%d: before freeing: %d mbufs in packet being freed\n",mynor,
+ 			c);
+ 	}
+ #endif
+ 	m_freem(m);
+ #if 0
+ 	if(ifp->if_flags & IFF_DEBUG) {
+ 		int c;
+ 		struct mbuf *mb;
+ 
+ 		for(mb=mmbfree, c=0 ; mb!=0; mb=mb->m_next)
+ 			c++;
+ 
+ 		printf("loe%d: after freeing: %d mbufs free\n",mynor,
+ 			c);
+ 	}
+ #endif
+ 	if(ifp->if_flags & IFF_DEBUG) {
+ 		printf("loe%d: read a packet\n",mynor);
+ 	}
+ 
+ 	splx(s);
+ 	return 0;
+ }
+ 
+ static int 
+ loecwrite(dev, uio, flag)
+ 	dev_t dev;
+ 	struct uio *uio;
+ 	int flag;
+ {
+ 	struct mbuf *m;
+ 	int mynor=minor(dev);
+ 	int s;
+ 	int error;
+     struct ifnet *ifp;
+ 	static char buf[ETHER_MAX_LEN];
+ 	int len;
+ 
+ 	ifp = &loearp[mynor].ac_if;
+ 
+ 	if(ifp->if_flags & IFF_DEBUG) {
+ 		printf("loe%d: write, isopen=%d\n",mynor, loeinfo[mynor].isopen);
+ 	}
+ 
+ 	if( (len=uio->uio_resid) > ETHER_MAX_LEN)
+ 		return ENOSPC;
+ 
+ 	s=splimp();
+ 	while(( m=m_gethdr(M_WAIT, MT_HEADER) )==0) {
+ 		if(loeinfo[mynor].fionbio) {
+ 			splx(s);
+ 			return EAGAIN;
+ 		}
+ 		if(ifp->if_flags & IFF_DEBUG) {
+ 			printf("loe%d: waiting for mbuf\n",mynor);
+ 		}
+ 		error=tsleep(&lbolt, (PZERO+1)|PCATCH, "loeget", 0);
+ 		if(error) {
+ 			splx(s);
+ 			return EINTR;
+ 		}
+ 	}
+ 
+ 	m->m_pkthdr.rcvif=0;
+ 	m->m_pkthdr.len=len;
+ 	error=uiomove(buf, len, uio);
+ 
+ 	if(error) {
+ 		m_freem(m);
+ 		splx(s);
+ 		return error;
+ 		}
+ 
+ 	m->m_len=min(MHLEN,len); /* prepare for m_copyback() */
+ 	m_copyback(m, 0, len, buf);
+ 
+ 	IF_ENQUEUE(&ifp->if_snd, m);
+ 	splx(s);
+ 
+ 	loestart(ifp);
+ 
+ 	return 0;
+ }
+ 
+ static int 
+ loecselect(dev, rw, p)
+ 	dev_t dev;
+ 	int rw;
+ 	struct proc *p;
+ {
+ 	int mynor=minor(dev);
+     struct ifnet *ifp;
+ 
+ 	ifp = &loearp[mynor].ac_if;
+ 
+ 	switch(rw) {
+ 	case FWRITE: /* writing is possible at any time */
+ 		return 1;
+ 		break;
+ 	case FREAD:
+ 		if(loeinfo[mynor].q.ifq_head!=0) {
+ 			return 1;
+ 		} else {
+ 			loeinfo[mynor].wantselect=1;
+ 			selrecord(p, &loeinfo[mynor].si);
+ 		}
+ 		break;
+ 	}
+ 	return 0;
+ }
+ 
+ static int
+ loecioctl(dev, cmd, arg, flag, p)
+ 	dev_t dev;
+ 	int cmd;
+ 	caddr_t arg;
+ 	int flag;
+ 	struct proc *p;
+ {
+ 	int mynor=minor(dev);
+     struct ifnet *ifp;
+     struct ifreq *ifr = (struct ifreq *) arg;
+ 
+ 	ifp = &loearp[mynor].ac_if;
+ 
+ 	switch(cmd) {
+ 	case FIONBIO:
+ 		loeinfo[mynor].fionbio=(int)arg;
+ 		break;
+ 	case FIOASYNC:
+ 		break;
+ 	case SIOCGIFADDR:
+ 		{ 
+ 		struct sockaddr *sa; 
+ 	 
+ 		if(ifp->if_flags & IFF_DEBUG)
+ 			printf("loe%d: character ioctl SIOCGIFADDR\n",mynor);
+ 
+ 		sa = (struct sockaddr *) & ifr->ifr_data;
+ 		bcopy((caddr_t) loearp[mynor].ac_enaddr, 
+ 			(caddr_t) sa->sa_data, ETHER_ADDR_LEN);
+ 		}
+ 		break;
+ 	default:
+ 		return ENODEV;
+ 	}
+ 	return 0;
+ }
+ 
+ #endif				/* NLOE > 0 */
*** /sys/i386/conf/LINT	Thu Oct 24 15:06:07 1996
--- /sys/i386/conf/LINT	Thu Oct 24 15:09:52 1996
***************
*** 185,190 ****
--- 185,191 ----
  #  which throws away all packets sent and never receives any.  It is
  #  included for testing purposes.
  #  The `tun' pseudo-device implements the User Process PPP (iijppp)
+ #  The 'loe' pseudo-device implements the Ethernet-like loopback driver.
  #
  pseudo-device	ether			#Generic Ethernet
  pseudo-device	fddi			#Generic FDDI
***************
*** 195,200 ****
--- 196,202 ----
  pseudo-device	bpfilter	4	#Berkeley packet filter
  pseudo-device	disc			#Discard device
  pseudo-device	tun	1		#Tunnel driver(user process ppp)
+ pseudo-device	loe 4		#Ethernet-like loopback
  
  #
  # Internet family options:
*** /sys/conf/files	1996/06/22 17:13:59	1.1
--- /sys/conf/files	1996/06/22 17:14:19
***************
*** 144,149 ****
--- 144,150 ----
  net/if_ethersubr.c	optional ether
  net/if_fddisubr.c	optional fddi
  net/if_loop.c		optional loop
+ net/if_loe.c		optional loe
  net/if_ppp.c		optional ppp
  net/if_sl.c		optional sl
  net/if_spppsubr.c	optional sppp
*** /sys/i386/conf/majors.i386	1996/10/24 10:14:31	1.1
--- /sys/i386/conf/majors.i386	1996/10/24 10:15:25
***************
*** 113,115 ****
--- 113,116 ----
  73	qcam		quickcam
  74	ccd		concatenated disk
  75	stli		Stallion (intelligent cdk based) (gerg@stallion.oz.au)
+ 77  loe		Ethernet-like loopback
*** /dev/MAKEDEV	1996/10/24 10:18:08	1.1
--- /dev/MAKEDEV	1996/10/24 10:20:25
***************
*** 98,103 ****
--- 98,104 ----
  #	isdn*	ISDN devices
  #	labpc*	National Instrument's Lab-PC and LAB-PC+
  #	perfmon	CPU performance-monitoring counters
+ #	loe*	“Ethernet-like loopback interface
  #
  #	$Id: MAKEDEV,v 1.1 1996/10/24 10:18:08 root Exp root $
  #
***************
*** 710,715 ****
--- 711,723 ----
  	rm -f bpf$unit
  	mknod bpf$unit c 23 $unit
  	chown root.wheel bpf$unit
+ 	;;
+ 
+ loe*)
+ 	unit=`expr $i : 'loe\(.*\)'`
+ 	rm -f loe$unit
+ 	mknod loe$unit c 77 $unit
+ 	chown root.wheel loe$unit
  	;;
  
  speaker)
*** /usr/share/FAQ/Text/loe.FAQ	Thu Oct 24 19:36:17 1996
--- /usr/share/FAQ/Text/loe.FAQ	Thu Oct 24 15:39:37 1996
***************
*** 0 ****
--- 1,62 ----
+ Loopback Ethernet-simuating interface FAQ
+ 
+ The design of this driver pursued two purposes:
+ 
+ 1. Get the testing environment for debugging of the networking
+ programs without a real network (like the configuration I have at home).
+ 
+ 2. Allow the programs in the MS-DOS emulation box to work with the
+ network.
+ 
+ Both of them are achieved now. It allows even two DOS boxes to
+ converse.
+ 
+ The driver consists of two parts: the network part and the character
+ part. The first one is used for hte information interchange with
+ FreeBSD, the second one is used for DOS boxes. The character
+ part allows to send and receive raw Ethernet packets so it can
+ be easily used by any other software.
+ 
+ To install the driver do the following:
+ 
+ add the line like
+ 
+ 	pseudo-device loe 4
+ 
+ from /sys/i386/conf/LINT to your configuration file. Rebuild the
+ kernel and reboot. Go to the /dev directory and run
+ 
+ 	sh MAKEDEV loe0
+ 	...
+ 	sh MAKEDEV loe3
+ 
+ This example assumes that you have configured 4 devices
+ as shown earlier. Note that to use this driver usefully at
+ least 2 devices must be configured to get the information
+ interchange between them.
+ 
+ Then PCEMU (the properly patched version) can be runned like:
+ 
+ 	pcemu -n /dev/loe1
+ 
+ PCEMU contains the built-in packet driver at interrupt 0x60,
+ so any software that can use the packet driver can be runned.
+ To run IPX networking you can use the PDIPX program. It is
+ copyrighted by Novell so it can't be included into the
+ distribution.
+ 
+ It's suggested to configure the loe0 device as the FreeBSD interface.
+ All other loe devices may be used to run PCEMU sessions. So if
+ 4 loe devices are configured then upto 3 PCEMUs
+ with network connection can be runned simultaneously.
+ 
+ If you run any IP implementations in the PCEMU boxes then don't
+ forget to use unique IP addresses for each concurrent PCEMU.
+ 
+ To get connected from PCEMU to other machines in the (real)
+ network a proper router must be running on the FreeBSD machine
+ and the routing to the PCEMU addresses via the FreeBSD machine
+ must be installed on the external machines (and obviously the
+ software runned in PCEMU must allow routing).
+ 
+ Serge A. Babkin <babkin@hq.icb.chel.su>



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199610241040.QAA08864>