Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 17 May 1998 14:01:30 -0400
From:      Sergey Babkin <babkin@bellatlantic.net>
To:        FreeBSD-gnats-submit@FreeBSD.ORG
Subject:   kern/6668: loe
Message-ID:  <355F25FA.41C67EA6@bellatlantic.net>

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

>Number:         6668
>Category:       kern
>Synopsis:       New Loopback Ethernet driver
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          open
>Quarter:
>Keywords:
>Date-Required:
>Class:          change-request
>Submitter-Id:   current-users
>Arrival-Date:   Sun May 17 11:00:00 PDT 1998
>Last-Modified:
>Originator:     Sergey Babkin <sab123@hotmail.com>
>Organization:
None
>Release:        FreeBSD current
>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)
>Audit-Trail:
>Unformatted:
X-send-pr-version: 3.2



To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-bugs" in the body of the message



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?355F25FA.41C67EA6>