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>
index | next in thread | raw e-mail
>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
help
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?355F25FA.41C67EA6>
