From babkin@bellatlantic.net  Sun May 17 11:02:52 1998
Received: from iconmail.bellatlantic.net (iconmail.bellatlantic.net [199.173.162.30])
          by hub.freebsd.org (8.8.8/8.8.8) with ESMTP id LAA20179
          for <FreeBSD-gnats-submit@freebsd.org>; Sun, 17 May 1998 11:02:50 -0700 (PDT)
          (envelope-from babkin@bellatlantic.net)
Received: from bird (client-151-200-127-235.bellatlantic.net [151.200.127.235])
	by iconmail.bellatlantic.net (IConNet Sendmail) with SMTP id OAA14915
	for <FreeBSD-gnats-submit@freebsd.org>; Sun, 17 May 1998 14:00:08 -0400 (EDT)
Message-Id: <355F25FA.41C67EA6@bellatlantic.net>
Date: Sun, 17 May 1998 14:01:30 -0400
From: Sergey Babkin <babkin@bellatlantic.net>
Sender: root@iconmail.bellatlantic.net
To: FreeBSD-gnats-submit@freebsd.org
Subject: loe

>Number:         6668
>Category:       kern
>Synopsis:       [patch] new driver: Virtual Ethernet driver
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    babkin
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          change-request
>Submitter-Id:   current-users
>Arrival-Date:   Sun May 17 11:00:00 PDT 1998
>Closed-Date:    Mon Nov 19 18:23:26 UTC 2007
>Last-Modified:  Mon Nov 19 18:23:26 UTC 2007
>Originator:     Sergey Babkin <sab123@hotmail.com>
>Release:        FreeBSD current
>Organization:
None
>Environment:

        FreeBSD-current. Tested with 3.0-980222-SNAP.

>Description:

        New Loopback Ethernet driver

>How-To-Repeat:

>Fix:
        
*** /dev/MAKEDEV        1998/04/12 06:24:00     1.1
--- /dev/MAKEDEV        1998/05/17 17:04:44
***************
*** 1148,1153 ****
--- 1148,1162 ----
        umask 77
        ;;
  
+ # use as MAKEDEV loeN to create N entries
+ loe*)
+       chr=98
+       units=`expr $i : 'loe\(.*\)'`
+       eval `echo ${chr} ${units} | awk ' { c=$1; n=$2 } END {
+               for (i = 0; i < n; i++)
+                       printf("mknod loe%d c %d %d;", i, c, i); }'`
+       ;;
+ 
  *)
        echo $i - no such device name
        ;;
*** /dev/null   Sun May 17 12:41:06 1998
--- /sys/net/if_loe.c   Sun May 17 13:01:08 1998
***************
*** 0 ****
--- 1,774 ----
+ /*
+  * Copyright (c) 1996-1998
+  *    Sergey 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.
+  *
+  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
IMPLIED
+  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES
OF
+  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+  *
+  * Loopback Ethernet-simulating interface
+  *
+  * Sergey A. Babkin (sab123@hotmail.com, babkin@bellatlantic.net)
+  *
+  */
+ 
+ #include "loe.h"
+ #if NLOE > 0
+ 
+ #include "opt_atalk.h"
+ #include "opt_inet.h"
+ #include "opt_ipx.h"
+ #include "opt_devfs.h"
+ 
+ #include "bpfilter.h"
+ 
+ #include <sys/param.h>
+ #if defined(__FreeBSD__)
+ #include <sys/systm.h>
+ #include <sys/kernel.h>
+ #include <sys/conf.h>
+ #include <sys/poll.h>
+ #include <sys/devconf.h>
+ #endif
+ #include <sys/malloc.h>
+ #include <sys/mbuf.h>
+ #include <sys/socket.h>
+ #include <sys/sockio.h>
+ #include <sys/errno.h>
+ #include <sys/syslog.h>
+ #include <sys/proc.h>
+ #include <sys/fcntl.h>
+ #include <sys/filio.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
+ 
+ #ifdef ISO
+ #include <netiso/iso.h>
+ #include <netiso/iso_var.h>
+ #endif
+ 
+ #ifdef NETATALK
+ #include <netatalk/at.h>
+ #include <netatalk/at_var.h>
+ #endif NETATALK
+ 
+ #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_poll_t loecpoll;
+ static d_ioctl_t loecioctl;
+ 
+ #define CDEV_MAJOR 98
+ static struct cdevsw loe_cdevsw = {
+       loecopen, loecclose, loecread, loecwrite,
+       loecioctl, nullstop, noreset, nodevtotty,
+       loecpoll, 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;
+ 
+               /* fill the arpcom Ethernet address */
+               ethaddr[5]=i+1; 
+               bcopy(ethaddr, &loearp[i].ac_enaddr, ETHER_ADDR_LEN);
+ 
+               if_attach(ifp);
+               ether_ifattach(ifp);
+ 
+ #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) {
+ #if NBPFILTER > 0
+                                       /* normally interface goes
promisc only for BPF */
+                                       /* but passing packet honestly
leads to duplicate */
+                                       /* response from IP layer */
+                                       if (loearp[i].ac_if.if_bpf) {
+                                              
bpf_mtap(&loearp[i].ac_if, m);
+                                       } else {
+                                              
loeread(&loearp[i].ac_if, m);
+                                       }
+ #else
+                                       loeread(&loearp[i].ac_if, m);
+ #endif
+                       }
+               }
+       }
+ 
+       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_NOWAIT);
+ 
+       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_NOWAIT);
+               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 | IFF_RUNNING;
+ 
+               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 
+ loecpoll(dev, events, p)
+       dev_t dev;
+       int events;
+       struct proc *p;
+ {
+       int mynor=minor(dev);
+       struct ifnet *ifp;
+       int revents=0;
+ 
+ #define POLL_FREAD (POLLIN|POLLPRI|POLLRDNORM|POLLRDBAND)
+ #define POLL_FWRITE (POLLOUT|POLLWRNORM|POLLWRBAND)
+ 
+       ifp = &loearp[mynor].ac_if;
+ 
+       if(events & POLL_FWRITE)
+               revents |= (events & POLL_FWRITE);
+ 
+       if(events & POLL_FREAD) {
+               if(loeinfo[mynor].q.ifq_head!=0) {
+                       return revents | (events & POLL_FREAD);
+               } else {
+                       loeinfo[mynor].wantselect=1;
+                       selrecord(p, &loeinfo[mynor].si);
+               }
+       }
+       return revents;
+ }
+ 
+ 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 */
*** /dev/null   Sun May 17 12:41:06 1998
--- /usr/share/man/man4/loe.4   Sun May 17 13:39:47 1998
***************
*** 0 ****
--- 1,70 ----
+ .\" Copyright (c) 1983, 1991, 1993
+ .\"   The Regents of the University of California.  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.
+ .\" 3. All advertising materials mentioning features or use of this
software
+ .\"    must display the following acknowledgement:
+ .\"   This product includes software developed by the University of
+ .\"   California, Berkeley and its contributors.
+ .\" 4. Neither the name of the University nor the names of its
contributors
+ .\"    may be used to endorse or promote products derived from this
software
+ .\"    without specific prior written permission.
+ .\"
+ .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS
IS'' AND
+ .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE
+ .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE
+ .\" ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
LIABLE
+ .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL
+ .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
GOODS
+ .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION)
+ .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT
+ .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY
+ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF
+ .\" SUCH DAMAGE.
+ .\"
+ .\"     @(#)lo.4      8.1 (Berkeley) 6/5/93
+ .\"   $Id: lo.4,v 1.5 1997/02/22 13:24:37 peter Exp $
+ .\"
+ .Dd May 17, 1998
+ .Dt LOE 4
+ .Os FreeBSD
+ .Sh NAME
+ .Nm loe
+ .Nd software loopback network interface with Ethernet emulation
+ .Sh SYNOPSIS
+ .Sy pseudo-device loe N
+ .Sh DESCRIPTION
+ The
+ .Nm loe
+ interface is a software loopback mechanism which may be
+ used for network support in emulators, software testing, and/or local
+ communication.
+ All the configured interfaces are connected to the same virtual
+ Ethernet segment. For any use at least two interfaces must be
+ configured.
+ The loe driver has both network and character interfaces. The
character
+ interface is intended to be used in emulators, the network interface
+ is intended to be used by the FreeBSD network protocols. The character
+ and network interfaces with the same number are connected to the same
+ virtual Ethernet card and must not be used both at the same time.
+ .Sh FILES
+ .Bl -tag -width /dev/loe? -compact
+ .It Pa /dev/loe?
+ character interfaces
+ .Sh SEE ALSO
+ .Xr lo 4 ,
+ .Xr inet 4 ,
+ .Xr intro 4
+ .Sh HISTORY
+ The
+ .Nm loe
+ device suport appeared in the
+ .Nm pcemu 1.92
+ PC emulator.
*** /sys/conf/files     1998/04/19 12:28:44     1.1
--- /sys/conf/files     1998/04/28 13:24:24
***************
*** 203,208 ****
--- 203,209 ----
  net/if_disc.c         optional disc
  net/if_ethersubr.c    optional ether
  net/if_fddisubr.c     optional fddi
+ net/if_loe.c          optional loe
  net/if_loop.c         optional loop
  net/if_media.c                standard
  net/if_mib.c          standard
*** /sys/i386/conf/LINT 1998/05/17 17:46:03     1.1
--- /sys/i386/conf/LINT 1998/05/17 17:48:40
***************
*** 363,368 ****
--- 363,370 ----
  #  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' pseudodevice simulates a number of Ethernet interfaces
+ #  connected to a common virtual network segment.
  #
  # The PPP_BSDCOMP option enables support for compress(1) style entire
  # packet compression, the PPP_DEFLATE is for zlib/gzip style
compression.
***************
*** 379,384 ****
--- 381,387 ----
  pseudo-device tun     1               #Tunnel driver (user process
ppp(8))
  pseudo-device sl      2               #Serial Line IP
  pseudo-device ppp     2               #Point-to-point protocol
+ pseudo-device loe     4               #Loopback Ethernet
  options PPP_BSDCOMP                   #PPP BSD-compress support
  options PPP_DEFLATE                   #PPP zlib/deflate/gzip support
  options PPP_FILTER                    #enable bpf filtering (needs
bpfilter)
>Release-Note:
>Audit-Trail:
State-Changed-From-To: open->feedback 
State-Changed-By: phk 
State-Changed-When: Sun May 17 23:00:21 PDT 1998 
State-Changed-Why:  
Uhm, can you briefly explain what use this is ? 
State-Changed-From-To: feedback->suspended 
State-Changed-By: phk 
State-Changed-When: Tue May 19 02:10:33 PDT 1998 
State-Changed-Why:  
ready for committer 

From: Luigi Rizzo <luigi@iet.unipi.it>
To: freebsd-gnats-submit@freebsd.org, babkin@bellatlantic.net
Cc:  Subject: Re: kern/6668: [PATCH] new driver: Virtual Ethernet driver
Date: Sun, 27 Dec 1998 13:48:26 +0100

 Re. phk request for explaination: i think the "loe" driver
 is the level-2 equivalent of the loopback driver. So it
 probably has its reasons to exist.
 
 	luigi

From: Sergey Babkin <babkin@bellatlantic.net>
To: Luigi Rizzo <luigi@iet.unipi.it>
Cc: freebsd-gnats-submit@freebsd.org
Subject: Re: kern/6668: [PATCH] new driver: Virtual Ethernet driver
Date: Sun, 27 Dec 1998 10:46:08 -0500

 Luigi Rizzo wrote:
 > 
 > Re. phk request for explaination: i think the "loe" driver
 > is the level-2 equivalent of the loopback driver. So it
 > probably has its reasons to exist.
 
 Yes. It is doing loopback on the Ethernet level, and also provides
 multiple interfaces connected to the same virtual Ethernet bus. I see 2
 reasons for it to exist:
 
 1. For development and debugging, to simulate Ethernet on a networkless
 machine.
 
 2. For the network code of the emulators. I wrote the support for pcemu
 and Mike Smith has included it into his updated version of pcemu, but
 this version was never released, as Mike says, because Bochs (i'm not sure
 about spelling) became available.
 
 -SB

From: Luigi Rizzo <luigi@labinfo.iet.unipi.it>
To: babkin@bellatlantic.net (Sergey Babkin)
Cc: luigi@iet.unipi.it, freebsd-gnats-submit@freebsd.org
Subject: Re: kern/6668: [PATCH] new driver: Virtual Ethernet driver
Date: Sun, 27 Dec 1998 14:38:36 +0100 (MET)

 > > Re. phk request for explaination: i think the "loe" driver
 > > is the level-2 equivalent of the loopback driver. So it
 > > probably has its reasons to exist.
 > 
 > Yes. It is doing loopback on the Ethernet level, and also provides
 > multiple interfaces connected to the same virtual Ethernet bus. I see 2
 > reasons for it to exist:
 
 I actually see one more use for experiments etc because one can slightly
 modify it to emulate wireless devices and do experiments with them.
 
 	luigi
Responsible-Changed-From-To: freebsd-bugs->babkin 
Responsible-Changed-By: jesper 
Responsible-Changed-When: Sun May 27 17:04:26 PDT 2001 
Responsible-Changed-Why:  
Originator is a committer himself 

http://www.FreeBSD.org/cgi/query-pr.cgi?pr=6668 
State-Changed-From-To: suspended->feedback 
State-Changed-By: kmacy 
State-Changed-When: Sun Nov 18 22:38:17 UTC 2007 
State-Changed-Why:  

Can I close this?  

http://www.freebsd.org/cgi/query-pr.cgi?pr=6668 
State-Changed-From-To: feedback->closed 
State-Changed-By: kmacy 
State-Changed-When: Mon Nov 19 18:22:57 UTC 2007 
State-Changed-Why:  

Submitter is no longer interested in this. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=6668 
>Unformatted:
