MOL Ethernet Patch (mol-0.9.47)


Subject: MOL Ethernet Patch (mol-0.9.47)
From: Bill Fink (billfink@capu.net)
Date: Mon Jun 05 2000 - 18:37:19 MDT


I wanted to be able to communicate directly between the Linux and MOL
sides of my system without having to use the tap interface, so I devised
the enclosed patch to MOL to accomplish this. The way it does this is
to give MOL a unique Ethernet address by setting the locally defined
Ethernet address bit and then using the SIOCADDMULTI ioctl to tell the
Ethernet hardware to listen for this additional Ethernet address. This
is admittedly a kludge since the address is not really a multicast
address. This is not a general solution and will not work on all
Ethernet hardware and drivers. It depends on the address recognition
logic of the Ethernet hardware being able to operate on any arbitrary
bit string and not specially interpreting or enforcing the setting of
the multicast Ethernet address bit. I can only vouch that it works
extremely well on my system, which uses an Asante Fast PCI 10/100
Ethernet adapter with the tulip driver on a 2.2.15pre20 kernel
(/proc/pci reports it as a DEC DC21140 Ethernet controller).
Unfortunately, because of a lack of proper error notification by
some of the kernel's Ethernet drivers, it is not always possible to
determine if the setting of the unique MOL Ethernet address is actually
successful. The best approach is to just try it out and see if it
works. To enable the code, all that is required after applying the
patch, and building and installing MOL, is to change the parameter
unique_mol_ethernet in the /etc/molrc file from no to yes (remember to
save your original molrc file before the install step and reapplying
any local changes to the new /etc/molrc file).

The code takes advantage of Charles McLachlan's idea of IP filtering,
but instead applies it at the MAC layer. This has the advantage of
filtering out not only TCP and UDP packets, but also any other packets
which aren't meant for MOL, such as ICMP packets from pings. I slightly
modified Charle's code to allow multicast packets through to support any
MacOS applications that use IP multicast or broadcast (although this is
probably fairly uncommon in the MacOS world). I also removed an
skb_pull call that was right before a kfree_skb call.

There is also a bug fix to sheep_net_receiver. Previously, despite
the comment to the contrary, any IP packets that had been generated
by MOL (marked by PROT_MAGIC) were unconditionally passed to ip_rcv
on the Linux side, regardless of where they were actually destined.
This meant that if these packets were intended for some other host
on the local network, the Linux side of the local system received
these unnecessary packets. Even worse, if IP forwarding happened
to be set, the Linux side would forward these packets on to the actual
destination host and send an ICMP redirect packet back to the MOL side.
Aside from the ICMP redirects, which would further load down MOL and
exacerbate any buffer depletion problems, this results in duplicate
packets arriving at the actual destination host. The patch fixes this
by filtering out any non-multicast packets that aren't destined for
the local host (by checking the last two bytes of the Ethernet address).
This has an additional advantage if the Ethernet interface is in
promiscuous mode for any reason, by keeping any unnecessary packets
from being forwarded to MOL.

Finally, all the normal disclaimers apply, including of course that
I assume absolutely no responsibility whatsoever for any negative
impact on your system or local network. Although YMMV depending on
your Ethernet hardware and driver, if you're lucky enough to have
the right kind, this patch should allow you to easily communicate
via TCP/IP between the Linux and MOL sides of your system, and to
improve the filtering of received packets being sent through to MOL.

                                                -Bill Fink

P.S. The patch is enclosed inline since the list server seems to be
      stripping attachments.

MOL Ethernet Patch (mol-0.9.47):
------------------------------------------------------------------------
diff -ur mol-0.9.47/Doc/molrc.sample mol-0.9.47+/Doc/molrc.sample
--- mol-0.9.47/Doc/molrc.sample Sat Jun 3 12:22:36 2000
+++ mol-0.9.47+/Doc/molrc.sample Mon Jun 5 15:47:43 2000
@@ -132,6 +132,12 @@
 disable_osi_enet: no
 enet_interface: eth0
 
+# Attempt to give MOL a unique Ethernet address by setting the locally
+# defined Ethernet address bit (this will not work on all Ethernet
+# hardware and drivers)
+#
+unique_mol_ethernet: no
+
 
 #######################################
 # Video configuration
diff -ur mol-0.9.47/drivers/osi_enet.c mol-0.9.47+/drivers/osi_enet.c
--- mol-0.9.47/drivers/osi_enet.c Sat Jun 3 12:22:37 2000
+++ mol-0.9.47+/drivers/osi_enet.c Mon Jun 5 16:04:36 2000
@@ -52,6 +52,9 @@
 /* Queue size for the rx thread. Should perhaps grow dynamically */
 #define RX_QUEUE_SIZE 32
 
+#define ETH_ADDR_MULTICAST 0x1
+#define ETH_ADDR_LOCALLY_DEFINED 0x2
+
 /************************************************************************/
 /* PCI constants (XXX: hardcoded to slot C1) */
 /************************************************************************/
@@ -122,6 +125,7 @@
         
         /* Ethernet address */
         unsigned char eth_addr[6];
+ int mol_ether_mcaddr;
         
         int tx_irq_level;
         int rx_irq_level;
@@ -142,6 +146,8 @@
 static interface_state_t is[1];
 
 static int initialized=0; /* set to 1 if initialized */
+static int unique_mol_ethernet=0; /* if set to 1, attempts to give */
+ /* MOL a unique Ethernet address */
 
 driver_interface_t osi_enet_driver =
 {
@@ -236,7 +242,49 @@
         
         /* Get Ethernet address */
         ioctl(is->net_dev, SIOCGIFADDR, is->eth_addr);
- LOG("Ethernet address is: %02x %02x %02x %02x %02x %02x\n",
+
+ unique_mol_ethernet = (get_bool_res("unique_mol_ethernet") == 1);
+ is->mol_ether_mcaddr = 0;
+ if (unique_mol_ethernet) {
+ /* Give MOL a unique Ethernet address by setting the
+ * locally defined Ethernet address bit, but first
+ * check that Ethernet address doesn't already have
+ * the bit set
+ */
+ if (is->eth_addr[0] & ETH_ADDR_LOCALLY_DEFINED) {
+ LOG("-----> Can't create unique MOL Ethernet address because\n");
+ LOG(" Ethernet address already has locally defined\n");
+ LOG(" Ethernet address bit set.\n");
+ LOG(" Will use IP filtering to filter out packets not\n");
+ LOG(" destined for Linux side.\n");
+
+ unique_mol_ethernet = 0;
+ }
+ else {
+ is->eth_addr[0] |= ETH_ADDR_LOCALLY_DEFINED;
+
+ /* Tell the Ethernet hardware that it needs to
+ * listen for the MOL Ethernet address
+ */
+ if (ioctl(is->net_dev, SIOCADDMULTI, is->eth_addr) < 0) {
+ LOG("-----> Can't add MOL Ethernet address as multicast address.\n");
+ LOG(" Will use IP filtering to filter out packets not\n");
+ LOG(" destined for Linux side.\n");
+
+ unique_mol_ethernet = 0;
+
+ /* Revert back to normal Ethernet
+ * hardware address
+ */
+ is->eth_addr[0] &= ~ETH_ADDR_LOCALLY_DEFINED;
+ }
+ else {
+ is->mol_ether_mcaddr = 1;
+ }
+ }
+ }
+
+ LOG("MOL Ethernet address is: %02x %02x %02x %02x %02x %02x\n",
                 is->eth_addr[0], is->eth_addr[1], is->eth_addr[2],
                 is->eth_addr[3], is->eth_addr[4], is->eth_addr[5]);
 
@@ -312,6 +360,16 @@
         os_interface_remove_proc( OSI_ENET_SEND_PACKET );
         os_interface_remove_proc( OSI_ENET_ADD_MULTI );
         os_interface_remove_proc( OSI_ENET_DEL_MULTI );
+
+ if (is->mol_ether_mcaddr) {
+ /* Remove MOL Ethernet address from hardware address list */
+ LOG("Removing MOL Ethernet address: %02x %02x %02x %02x %02x %02x\n",
+ is->eth_addr[0], is->eth_addr[1], is->eth_addr[2],
+ is->eth_addr[3], is->eth_addr[4], is->eth_addr[5]);
+ if (ioctl(is->net_dev, SIOCDELMULTI, is->eth_addr) < 0) {
+ LOG("WARNING: Can't remove MOL Ethernet address from multicast address list\n");
+ }
+ }
 
         /* Close sheep_net driver */
         if (is->net_dev > 0)
diff -ur mol-0.9.47/netdriver/sheep.c mol-0.9.47+/netdriver/sheep.c
--- mol-0.9.47/netdriver/sheep.c Sat Jun 3 12:22:37 2000
+++ mol-0.9.47+/netdriver/sheep.c Mon Jun 5 16:37:30 2000
@@ -34,6 +34,9 @@
 #define MAX_QUEUE 32 // Maximum number of packets in queue
 #define PROT_MAGIC 1520 // Our "magic" protocol type
 
+#define ETH_ADDR_MULTICAST 0x1
+#define ETH_ADDR_LOCALLY_DEFINED 0x2
+
 // Prototypes
 static int sheep_net_open(struct inode *inode, struct file *f);
 static int sheep_net_release(struct inode *inode, struct file *f);
@@ -95,6 +98,9 @@
         NULL
 };
 
+static int unique_mol_ethernet=0; /* set to 1 when MOL has a */
+ /* unique Ethernet address */
+
 
 /*
  * Initialize module
@@ -228,6 +234,7 @@
 
 #include <net/arp.h>
 #include <net/ip.h>
+#include <linux/in.h>
 
 /*
  * Driver write() function
@@ -270,29 +277,33 @@
         skb->priority = 0;
         skb->nh.raw = skb->h.raw = skb->data + v->ether->hard_header_len;
 
- // base our filter choice on only TCP or UDP IP packets
+ if (!unique_mol_ethernet) {
+ // base our filter choice on only TCP or UDP IP packets
 
- if ((skb->protocol == ETH_P_IP) &&
- ( (skb->nh.iph->protocol == 6) || (skb->nh.iph->protocol == 0x11) ))
- {
- if (skb->nh.iph->saddr != v->ipfilter) {
- int k;
-
- v->ipfilter = skb->nh.iph->saddr;
- bug("New filter : %08lx\n", v->ipfilter);
- bug("Filter packet: %02x %04x %04x %04x %02x %02x %04x %08x %08x\n",
- skb->nh.iph->tos, skb->nh.iph->tot_len, skb->nh.iph->id,
- skb->nh.iph->frag_off, skb->nh.iph->ttl,
- skb->nh.iph->protocol, skb->nh.iph->check,
- skb->nh.iph->saddr, skb->nh.iph->daddr );
- bug("Ether packet: (%d) ", v->ether->hard_header_len);
- for(k = 0; k < 14; k++) {
- bug("%02x", skb->data[k]);
- if ((k == 5) || (k == 11) || (k == 23))
- bug(",");
- }
- bug("\n");
- }
+ if ((skb->protocol == ETH_P_IP) &&
+ ( (skb->nh.iph->protocol == IPPROTO_TCP) ||
+ (skb->nh.iph->protocol == IPPROTO_UDP) ))
+ {
+ if (skb->nh.iph->saddr != v->ipfilter) {
+ int k;
+
+ v->ipfilter = skb->nh.iph->saddr;
+ bug("New filter : %08lx\n", v->ipfilter);
+ bug("Filter packet: %02x %04x %04x %04x %02x %02x %04x %08x %08x\n",
+ skb->nh.iph->tos, skb->nh.iph->tot_len,
+ skb->nh.iph->id, skb->nh.iph->frag_off,
+ skb->nh.iph->ttl, skb->nh.iph->protocol,
+ skb->nh.iph->check, skb->nh.iph->saddr,
+ skb->nh.iph->daddr );
+ bug("Ether packet: (%d) ", v->ether->hard_header_len);
+ for(k = 0; k < 14; k++) {
+ bug("%02x", skb->data[k]);
+ if ((k == 5) || (k == 11) || (k == 23))
+ bug(",");
+ }
+ bug("\n");
+ }
+ }
         }
         
         skb->protocol = PROT_MAGIC; // "Magic" protocol value to recognize our packets in sheep_net_receiver()
@@ -403,11 +414,19 @@
                 // arg: pointer to address (6 bytes)
                 case SIOCADDMULTI: {
                         char addr[6];
+ int ret;
                         if (v->ether == NULL)
                                 return -ENODEV;
                         if (copy_from_user(addr, (void *)arg, 6))
                                 return -EFAULT;
- return dev_mc_add(v->ether, addr, 6, 0);
+ ret = dev_mc_add(v->ether, addr, 6, 0);
+ if (ret == 0) {
+ // Check if setting unique MOL Ethernet address
+ if ((addr[0] & ETH_ADDR_LOCALLY_DEFINED) &&
+ !(addr[0] & ETH_ADDR_MULTICAST))
+ unique_mol_ethernet = 1;
+ }
+ return ret;
                 }
 
                 // Remove multicast address
@@ -448,7 +467,21 @@
         struct SheepVars *v = (struct SheepVars *)pt->data;
         D(bug("sheep_net: packet received\n"));
 
- // Packet sent by us? Then discard
+ // Check if packet isn't meant for this host, determined by checking
+ // that it's destination Ethernet address doesn't match this host's
+ // Ethernet address, and that it's not multicast. For efficiency
+ // purposes, checking only the last two bytes of the Ethernet address
+ // should be sufficient. The multicast case depends on upper layer
+ // filtering out MOL packets not destined for this host.
+ if ((*((u16 *)&skb->mac.ethernet->h_dest[4]) !=
+ *((u16 *)&v->ether->dev_addr[4])) &&
+ !(skb->mac.ethernet->h_dest[0] & ETH_ADDR_MULTICAST)) {
+ // Packet not meant for this host so discard
+ kfree_skb(skb);
+ return 0;
+ }
+
+ // Packet sent by us?
         if (skb->protocol == PROT_MAGIC) {
                 skb_pull(skb, v->ether->hard_header_len);
                 if (skb->data[0] == 0x00) {
@@ -463,14 +496,26 @@
                 return 0;
         }
 
- if ((skb->protocol == ETH_P_IP) && (v->ipfilter))
- {
- if (skb->h.ipiph->daddr != v->ipfilter)
- {
- skb_pull(skb, v->ether->hard_header_len);
- kfree_skb(skb);
- return 0;
- }
+ if (unique_mol_ethernet) {
+ if (!(skb->mac.ethernet->h_dest[0] &
+ (ETH_ADDR_LOCALLY_DEFINED | ETH_ADDR_MULTICAST))) {
+ // If the locally defined Ethernet address bit isn't set
+ // in the destination Ethernet address, and it isn't an
+ // Ethernet multicast destination, then packet must be
+ // destined for Linux side, so silently drop
+ kfree_skb(skb);
+ return 0;
+ }
+ } else {
+ if ((skb->protocol == ETH_P_IP) && (v->ipfilter))
+ {
+ if ((skb->h.ipiph->daddr != v->ipfilter) &&
+ !(skb->mac.ethernet->h_dest[0] & ETH_ADDR_MULTICAST))
+ {
+ kfree_skb(skb);
+ return 0;
+ }
+ }
         }
 
         // Discard packets if queue gets too full



This archive was generated by hypermail 2a24 : Mon Jun 05 2000 - 18:36:18 MDT