Hi,
I have donne a patch to make the network for plex86-Linux working. The
patch could be added to the last CVS version and it implements
eth_linux.cc using Linux Socket Filtering. I used a thread to make
readings from the socket in an infinite loop. I tested this networking
stuff only on Linux so if you test it on other OSes please tell me what
happend. I did small changes on ne2k.cc source and I don't know if the
changes works also on Free BSD where they worked before. Anyway,  in
order to test the patch do the followings:
-patch -p1 < plex86-net.patch
-autoconf
-./configure --enable-ne2000
-make
-add in the configuration file the next line:
bochs-opt ne2k: ioaddr=0x280, irq=10, mac=00:a:b:c:1:3, ethmod=linux,
ethdev=eth0

The unpleasent problem is that using this approach you cannot connect
the guest to the host(only guest<->others or guest<->guest). Finally you
should have(on Linux) compiled the modules 8390.o and ne.o
and do insmod 8390.0 insmod ne.o io=0x280.

Best Regards
Bogdan
diff -urN plex86/config.h.in plex86-net/config.h.in
--- plex86/config.h.in  Mon Jun 25 17:18:40 2001
+++ plex86-net/config.h.in      Mon Jun 25 17:27:29 2001
@@ -107,6 +107,7 @@
 #define BX_USE_SB16_SMF 1  /* Sound (SB 16) */
 #define BX_USE_DEV_SMF  1  /* System Devices (port92) */
 #define BX_USE_PCI_SMF  1  /* PCI */
+#define BX_USE_NE2K_SMF 0  /* NE2K */
  
 #define BX_SUPPORT_SB16 0
  
@@ -141,6 +142,7 @@
    /* low-level CDROM. */
 #  define LOWLEVEL_CDROM cdrom_interface
 #endif
+#define BX_NE2K_SUPPORT 0
 
 #define COSIMULATE 0
 #define BX_WITH_SDL 0
diff -urN plex86/configure.in plex86-net/configure.in
--- plex86/configure.in Mon Jun 25 17:18:40 2001
+++ plex86-net/configure.in     Fri Jun 22 15:43:59 2001
@@ -1,4 +1,4 @@
-dnl // Process this file with autoconf to produce a configure script.
+OSIM_EXTERNAL_LIBS
 
 AC_PREREQ(2.4)
 AC_INIT(ChangeLog)
@@ -36,6 +36,29 @@
 
 COSIM_O=''
 COSIM_EXTERNAL_LIBS=''
+
+AC_MSG_CHECKING(for NE2000 support)
+AC_ARG_ENABLE(ne2000,
+  [  --enable-ne2000                   enable limited ne2000 support],
+  [if test "$enableval" = yes; then
+    AC_MSG_RESULT(yes)
+    AC_DEFINE(BX_NE2K_SUPPORT, 1)
+    NE2K_OBJS='ne2k.o eth.o eth_null.o'
+        AC_CHECK_HEADER(linux/version.h, NE2K_OBJS="$NE2K_OBJS eth_linux.o")
+    AC_CHECK_HEADER(net/bpf.h, NE2K_OBJS="$NE2K_OBJS eth_fbsd.o")
+   else
+    AC_MSG_RESULT(no)
+    AC_DEFINE(BX_NE2K_SUPPORT, 0)
+    NE2K_OBJS=''
+   fi],
+  [
+    AC_MSG_RESULT(no)
+    AC_DEFINE(BX_NE2K_SUPPORT, 0)
+    NE2K_OBJS=''
+    ]
+  )
+AC_SUBST(NE2K_OBJS)
+
 AC_ARG_ENABLE(cosimulation,
   [  --enable-cosimulation             simulate in parallel with other sim],
   [if test "$enableval" = yes; then
@@ -249,7 +272,7 @@
 INSTRUMENT_DIR='instrument/'
 VIDEO_OBJS='$(VIDEO_OBJS_VGA)'
 PCI_OBJ=''
-NE2K_OBJS=''
+#NE2K_OBJS=''
 SB16_OBJS=''
 
 AC_SUBST(SUFFIX_LINE)
diff -urN plex86/user/plugins/bochs/Makefile.in 
plex86-net/user/plugins/bochs/Makefile.in
--- plex86/user/plugins/bochs/Makefile.in       Mon Jun 25 17:18:40 2001
+++ plex86-net/user/plugins/bochs/Makefile.in   Fri Jun 22 17:36:17 2001
@@ -49,7 +49,7 @@
        $(CXX) -fPIC -I../../.. -I$(srcdir)/../../.. -I$(srcdir)/../.. -I$(srcdir) 
$(CXXFLAGS) -c  $<
 
 plugin-bochs.so: io.o pc_system.o state_file.o iodev/libiodev.a gui/libgui.a
-       $(CXX) -shared -o plugin-bochs.so io.o pc_system.o state_file.o \
+       $(CXX) -lpthread -shared -o plugin-bochs.so io.o pc_system.o state_file.o \
                         iodev/libiodev.a gui/libgui.a \
                         @GUI_LINK_OPTS@
 
diff -urN plex86/user/plugins/bochs/iodev/Makefile.in 
plex86-net/user/plugins/bochs/iodev/Makefile.in
--- plex86/user/plugins/bochs/iodev/Makefile.in Mon Jun 25 17:18:40 2001
+++ plex86-net/user/plugins/bochs/iodev/Makefile.in     Fri Jun 22 15:12:25 2001
@@ -59,7 +59,8 @@
   parallel.o \
   serial.o \
   $(VIDEO_OBJS) \
-  @CDROM_OBJS@
+  @CDROM_OBJS@ \
+  @NE2K_OBJS@
 
 
 BX_IODEV_OBJS = $(BX_HW_IODEV_OBJS)
diff -urN plex86/user/plugins/bochs/iodev/eth.cc 
plex86-net/user/plugins/bochs/iodev/eth.cc
--- plex86/user/plugins/bochs/iodev/eth.cc      Mon Jun 25 17:18:40 2001
+++ plex86-net/user/plugins/bochs/iodev/eth.cc  Fri Jun 22 15:48:17 2001
@@ -59,16 +59,23 @@
 
 #ifdef ETH_NULL
   {
-    extern bx_null_match;
+    extern class bx_null_c bx_null_match;
     if (!strcmp(type, "null"))
       ptr = (eth_locator_c *) &bx_null_match; 
   }
 #endif
 #ifdef ETH_FBSD
   {
-    extern bx_fbsd_match;
+    extern class bx_fbsd_c bx_fbsd_match;
     if (!strcmp(type, "fbsd"))    
       ptr = (eth_locator_c *) &bx_fbsd_match;
+  }
+#endif
+#ifdef ETH_LINUX
+  {
+    extern class bx_linux_c bx_linux_match;
+    if (!strcmp(type, "linux"))    
+      ptr = (eth_locator_c *) &bx_linux_match;
   }
 #endif
 #ifdef ETH_TEST
diff -urN plex86/user/plugins/bochs/iodev/eth.h 
plex86-net/user/plugins/bochs/iodev/eth.h
--- plex86/user/plugins/bochs/iodev/eth.h       Mon Jun 25 17:18:40 2001
+++ plex86-net/user/plugins/bochs/iodev/eth.h   Fri Jun 22 15:46:41 2001
@@ -74,3 +74,6 @@
 #ifdef __FreeBSD__
 #define ETH_FBSD  1
 #endif
+#ifdef __linux__
+#define ETH_LINUX
+#endif
diff -urN plex86/user/plugins/bochs/iodev/eth_linux.cc 
plex86-net/user/plugins/bochs/iodev/eth_linux.cc
--- plex86/user/plugins/bochs/iodev/eth_linux.cc        Wed Dec 31 22:00:00 1969
+++ plex86-net/user/plugins/bochs/iodev/eth_linux.cc    Mon Jun 25 14:32:15 2001
@@ -0,0 +1,270 @@
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU Lesser General Public
+//  License as published by the Free Software Foundation; either
+//  version 2 of the License, or (at your option) any later version.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+// eth_linux.cc  - linux code for an ethernet pktmover
+
+// Bogdan Diaconescu ([EMAIL PROTECTED]) coded all of this
+// NE2000/ether stuff.
+//
+// eth_linux.cc is a Linux implementation of the ethernet packetmover. It uses
+// Linux Socket Filtering which is very close to BPF. I used a thread to poll
+// the socket in an infinite loop. Anyway there are somme problems with the
+// approach I choosed to implement the guest<->host interface:
+// - the guestOS is not able to connect with the hostOS.
+// - the host ethernet interface is put in promiscuous mode.
+//  
+//  ne2k: ioaddr=0x280, irq=10, mac=00:a:b:c:1:2, ethmod=linux, ethdev=eth0
+
+#include "bochs.h"
+
+extern "C" {
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <linux/if_ether.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netpacket/packet.h>
+#include <pcap/net/bpf.h>
+#include <errno.h>
+#include <pthread.h>
+};
+
+#define BX_BPF_INSNSIZ  8              // number of bpf insns
+
+static const struct bpf_insn macfilter[] = {
+  BPF_STMT(BPF_LD|BPF_W|BPF_ABS, 2),
+  BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 0xaaaaaaaa, 0, 2),
+  BPF_STMT(BPF_LD|BPF_H|BPF_ABS, 0),
+  BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 0x0000aaaa, 2, 0),
+  BPF_STMT(BPF_LD|BPF_B|BPF_ABS, 0),
+  BPF_JUMP(BPF_JMP|BPF_JSET|BPF_K, 0x01, 0, 1),
+  BPF_STMT(BPF_RET, 1514),
+  BPF_STMT(BPF_RET, 0),
+}; 
+
+#define ARPHRD_ETHER    1     /* Ethernet 10Mbps      */
+#define  ARPHRD_EETHER  2     /* Experimental Ethernet   */
+
+pthread_t pt;
+void* recv_th(void*);
+
+//
+//  define the class. This is private to this module
+//
+
+class bx_linux_pktmover_c : public eth_pktmover_c {
+public:
+  bx_linux_pktmover_c(const char *netif, const char *macaddr,
+                    eth_rx_handler_t rxh,
+                    void *rxarg);
+  void sendpkt(void *buf, unsigned io_len);
+       void rx_timer(void);
+private:       
+       char* linux_macaddr[6];
+       int bpf_fd;
+       struct bpf_insn filter[BX_BPF_INSNSIZ];
+       Bit8u* rxbuf;
+};
+
+
+bx_linux_pktmover_c* this_ptr;
+
+//
+//  Define the static class that registers the derived pktmover class,
+// and allocates one on request.
+//
+class bx_linux_locator_c : public eth_locator_c {
+public:
+  bx_linux_locator_c(void) : eth_locator_c("linux") {}
+protected:
+  eth_pktmover_c *allocate(const char *netif, const char *macaddr,
+                          eth_rx_handler_t rxh,
+                          void *rxarg) {
+    return (new bx_linux_pktmover_c(netif, macaddr, rxh, rxarg));
+  }
+} bx_linux_match;
+
+
+//
+// Define the methods for the bx_linux_pktmover derived class
+//
+
+// the constructor
+//
+// Open a socket and bind it to the interface
+//
+bx_linux_pktmover_c::bx_linux_pktmover_c(const char *netif, 
+                                      const char *macaddr,
+                                      eth_rx_handler_t rxh,
+                                      void *rxarg)
+{
+       char device[sizeof "ethXX"];
+       struct ifreq ifr, saved_ifr;
+       struct sockaddr_ll sl;
+       int linktype;
+       int mtu;
+       struct bpf_program bp;
+       
+       memcpy(linux_macaddr, macaddr, 6);
+       strcpy(device, netif);
+       bpf_fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
+       if (this->bpf_fd < 0) {
+    bx_printf ("ne2k: could not open socket: %s\n", strerror(errno));
+    return;
+  } 
+
+       /* get the interface index */
+       memset(&ifr, 0, sizeof(ifr));
+       strncpy(ifr.ifr_name, device, sizeof(ifr.ifr_name));
+       if (ioctl(this->bpf_fd, SIOCGIFINDEX, &ifr) < 0 ) {
+               bx_printf("ne2k: SIOCGIFINDEX: %s\n", strerror(errno));
+               close(this->bpf_fd);
+               return;
+       }
+       bx_printf("ne2k: interface index is %i\n", ifr.ifr_ifindex);
+
+       /* bind the socket to the interface */
+  memset(&sl, 0, sizeof(sl));
+  sl.sll_family = AF_PACKET;
+  sl.sll_protocol = htonl(ETH_P_ALL);
+  sl.sll_ifindex = ifr.ifr_ifindex;
+  if (bind(this->bpf_fd, (struct sockaddr*)&sl, sizeof(sl))) {
+    bx_printf("error binding interface %s: %s\n", device, strerror(errno));
+               close(this->bpf_fd);
+               return;
+  }
+
+       /* get the media link type */
+       memset(&ifr, 0, sizeof(ifr));
+       strncpy(ifr.ifr_name, device, sizeof(ifr.ifr_name));
+       if (ioctl(this->bpf_fd, SIOCGIFHWADDR, &ifr) < 0 ) {
+               bx_printf("ne2k: SIOCGIFHWADDR: %s\n", strerror(errno));
+               close(this->bpf_fd);
+               return;
+       }
+  switch (ifr.ifr_hwaddr.sa_family) {
+    case ARPHRD_ETHER:
+    case ARPHRD_EETHER:
+        linktype = DLT_EN10MB;
+        break;
+    default:
+      bx_printf("ne2k: found unknown media!\n");
+      return;
+  }
+       
+       /* Base the buffer size on the interface MTU */
+       memset(&ifr, 0, sizeof(ifr));
+       strncpy(ifr.ifr_name, device, sizeof(ifr.ifr_name));
+       if (ioctl(this->bpf_fd, SIOCGIFMTU, &ifr) < 0 ) {
+               bx_printf("ne2k: SIOCGIFMTU: %s", strerror(errno));
+               close(this->bpf_fd);
+               return;
+       }
+  mtu = ifr.ifr_mtu;
+  bx_printf("ne2k: MTU is %i\n", ifr.ifr_mtu);
+       /* alloc the RX buffer */
+       this->rxbuf = (Bit8u*)malloc(mtu + 64);
+
+       /* put the interface in promiscuous mode */
+  memset(&ifr, 0, sizeof(ifr));
+       strcpy(ifr.ifr_name, device);
+       if (ioctl(this->bpf_fd, SIOCGIFFLAGS, &ifr) < 0 ) {
+               bx_printf("ne2k: SIOCGIFFLAGS: %s", strerror(errno));
+               close(this->bpf_fd);
+    return;
+       }
+       saved_ifr = ifr;
+       ifr.ifr_flags |= IFF_PROMISC;
+       if (ioctl(this->bpf_fd, SIOCSIFFLAGS, &ifr) < 0 ) {
+               bx_printf("ne2k: SIOCSIFFLAGS: %s", strerror(errno));
+               close(this->bpf_fd);
+               return;
+       }
+       ifr.ifr_flags &= ~IFF_PROMISC;
+       bx_printf("ne2k: interface %s in promisc mode now\n", device);
+
+       /* now install the filter */
+       memcpy(&this->filter, macfilter, sizeof(macfilter));
+  this->filter[1].k = (macaddr[2] & 0xff) << 24 |
+    (macaddr[3] & 0xff) << 16 |
+    (macaddr[4] & 0xff) << 8  |
+    (macaddr[5] & 0xff);
+  this->filter[3].k = (macaddr[0] & 0xff) << 8 |
+    (macaddr[1] & 0xff);
+  bp.bf_len   = 8;
+  bp.bf_insns = &this->filter[0];
+  int ret;
+  ret = setsockopt(this->bpf_fd, SOL_SOCKET, SO_ATTACH_FILTER, &bp, sizeof(bp));  if 
+(ret < 0){
+    bx_printf("ne2k: setsockopt: %s\n", strerror(errno));
+               close(this->bpf_fd);
+    return;
+  }
+  bx_printf("ne2k: bpf filter registered\n");
+
+       /* start the RX poll using a thread */
+       pthread_create(&pt, NULL, recv_th, NULL);
+       this_ptr = this;
+
+       this->rxh   = rxh;
+  this->rxarg = rxarg; 
+}
+
+// the output routine - called with pre-formatted ethernet frame.
+void
+bx_linux_pktmover_c::sendpkt(void *buf, unsigned io_len)
+{
+       int status = 0;
+ 
+  if (this->bpf_fd != -1)
+    status = write(this->bpf_fd, buf, io_len);
+  if (status < 0)
+    bx_printf("ne2k: error on write packet: %s\n", strerror(errno));
+}
+
+
+void
+bx_linux_pktmover_c::rx_timer(void)
+{
+  int nbytes = 0;
+ 
+  nbytes = read(this->bpf_fd, this->rxbuf, 2048);
+  if (nbytes < 0)
+    bx_printf("ne2k: error on receive packet: %s\n", strerror(errno));
+
+#ifdef undef 
+  printf("packet rx (%d bytes):\n\t", nbytes);
+    for (int i = 0; i < nbytes; i++) {
+      printf("%02x ", rxbuf[i]);
+      if (i && (((i+1) % 16) == 0))
+       printf("\n\t");
+    }
+    printf("\n");
+#endif
+ 
+  if (nbytes > 0) {
+       (*rxh)(rxarg, rxbuf, nbytes);
+ }
+
+} 
+
+
+void* recv_th(void* args){
+       int i = 0;
+       do{
+               this_ptr->rx_timer();
+               i++;
+       }while(1);
+}
diff -urN plex86/user/plugins/bochs/iodev/ne2k.cc 
plex86-net/user/plugins/bochs/iodev/ne2k.cc
--- plex86/user/plugins/bochs/iodev/ne2k.cc     Mon Jun 25 17:18:40 2001
+++ plex86-net/user/plugins/bochs/iodev/ne2k.cc Mon Jun 25 12:56:38 2001
@@ -114,6 +114,7 @@
   if (value & 0x01) {
     BX_NE2K_THIS s.ISR.reset = 1;
     BX_NE2K_THIS s.CR.stop   = 1;
+    BX_NE2K_THIS s.CR.start = 0;
   } else {
     BX_NE2K_THIS s.CR.stop = 0;
   }
@@ -124,9 +125,9 @@
   // must be cleared
   if ((value & 0x02) && !BX_NE2K_THIS s.CR.start) {
     BX_NE2K_THIS s.ISR.reset = 0;
+       BX_NE2K_THIS s.CR.start = ((value & 0x02) == 0x02);
   }
 
-  BX_NE2K_THIS s.CR.start = ((value & 0x02) == 0x02);
   BX_NE2K_THIS s.CR.pgsel = (value & 0xc0) >> 6;
 
   // Check for start-tx
@@ -177,7 +178,7 @@
       BX_NE2K_THIS s.remote_bytes == 0) {
     BX_NE2K_THIS s.ISR.rdma_done = 1;
     if (BX_NE2K_THIS s.IMR.rdma_inte) {
-      BX_NE2K_THIS devices->pic->trigger_irq(BX_NE2K_THIS s.base_irq);
+       raise_interrupt(); 
     }
   }
 }
@@ -259,7 +260,7 @@
     // registers must have been initialised.
     //
     if (io_len != (1 + BX_NE2K_THIS s.DCR.wdsize))
-      bx_panic("ne2k: dma read, wrong size %d", io_len);
+      bx_printf("ne2k: dma read, wrong size %d", io_len);
 
     if (BX_NE2K_THIS s.remote_bytes == 0)
       bx_panic("ne2K: dma read, byte count 0");
@@ -859,7 +860,7 @@
   // Generate an interrupt if not masked and not one in progress
   if (BX_NE2K_THIS s.IMR.tx_inte && !BX_NE2K_THIS s.ISR.pkt_tx) {
     BX_NE2K_THIS s.ISR.pkt_tx = 1;
-    BX_NE2K_THIS devices->pic->trigger_irq(BX_NE2K_THIS s.base_irq);
+    raise_interrupt();
   }
   BX_NE2K_THIS s.tx_timer_active = 0;
 }
@@ -1083,7 +1084,7 @@
   }
 
   // Setup packet header
-  pkthdr[0] = 0;       // rx status
+  pkthdr[0] = 1;       // rx status
   pkthdr[1] = nextpage;        // ptr to next packet
   pkthdr[2] = (io_len + 8) & 0xff;     // length-low
   pkthdr[3] = (io_len + 8) >> 8;       // length-hi
@@ -1116,7 +1117,7 @@
   BX_NE2K_THIS s.ISR.pkt_rx = 1;
 
   if (BX_NE2K_THIS s.IMR.rx_inte) {
-    BX_NE2K_THIS devices->pic->trigger_irq(BX_NE2K_THIS s.base_irq);
+    raise_interrupt();
   }
 
 }
@@ -1194,3 +1195,9 @@
     }
   }
 }
+
+void
+bx_ne2k_c::raise_interrupt()
+{
+    pluginTriggerIRQ(BX_NE2K_THIS s.base_irq);
+} 
diff -urN plex86/user/plugins/bochs/iodev/ne2k.h 
plex86-net/user/plugins/bochs/iodev/ne2k.h
--- plex86/user/plugins/bochs/iodev/ne2k.h      Mon Jun 25 17:18:40 2001
+++ plex86-net/user/plugins/bochs/iodev/ne2k.h  Fri Jun 22 15:21:45 2001
@@ -202,6 +202,8 @@
 
   eth_pktmover_c *ethdev;
 
+       BX_NE2K_SMF void raise_interrupt();
+
   BX_NE2K_SMF void   reset_device(void);
   BX_NE2K_SMF Bit32u read_cr(void);
   BX_NE2K_SMF void   write_cr(Bit32u value);

Reply via email to