diff --git a/addons/rtnetproxy.c b/addons/rtnetproxy.c
index 2358d09..234f21b 100644
--- a/addons/rtnetproxy.c
+++ b/addons/rtnetproxy.c
@@ -23,6 +23,10 @@
  *
  * Changelog:
  *
+ * 14-Jan-2010  Vladimir Cotfas - Modified xmit function to return TX_BUSY to Linux.
+ *                                Instrumented code to track rtskb shortages.
+ *                                Tuned parameters for better performance w/ FTP.
+ *
  * 08-Nov-2002  Mathias Koehrer - Clear separation between rtai context and
  *                                standard linux driver context.
  *                                Data exchange via ringbuffers.
@@ -51,6 +55,7 @@
 #include <linux/if_ether.h> /* For the statistics structure. */
 #include <linux/if_arp.h>   /* For ARPHRD_ETHER */
 
+#include <linux/proc_fs.h>      // for the proc filesystem
 
 #include <rtdev.h>
 #include <rtskb.h>
@@ -70,11 +75,24 @@ MODULE_PARM_DESC(proxy_rtskbs, "Number of realtime socket buffers in proxy pool"
 
 static struct rtskb_queue rtskb_pool;
 
+static struct Stats {
+    volatile long rtskb_pool_empty;
+    volatile long rtskb_ringbuffer;
+    volatile long rtskb_ringbuffer_full;
+    volatile long rx_dropped;
+    volatile long rx_out;
+    volatile long tx_in;
+    volatile long tx_full;
+    volatile long tx_pending;
+} stats;
+
+static struct proc_dir_entry* procFileEntry;
 
 /* **************************************************************************
  *  SKB ringbuffers for exchanging data between rtnet and kernel:
  * ************************************************************************ */
-#define SKB_RINGBUFFER_SIZE 16
+//#define SKB_RINGBUFFER_SIZE 16
+#define SKB_RINGBUFFER_SIZE 256
 typedef struct
 {
     int wr;        // Offset to wr: Increment before write!
@@ -113,6 +131,57 @@ MODULE_PARM_DESC(rtdev_attach, "Attach to the specified RTnet device");
 struct rtnet_device *rtnetproxy_rtdev;
 #endif
 
+struct rtnetproxy_priv {
+    struct net_device* dev;
+};
+
+#define STATIC_BUF_LEN 40960
+
+static int procfile_read(char* buffer_UNUSED, char** start,
+                         off_t offset, int count,
+                         int* eof, void* data)
+{
+  static int len = 0;
+  static char s_buf[STATIC_BUF_LEN] = {0};
+  const int buf_cnt = STATIC_BUF_LEN - 1;
+  char* buf = s_buf;
+
+  if(offset > 0) {
+    *start = s_buf + offset;
+    *eof = (len >= offset) ? 0 : 1;
+    return eof ? (len - offset) : 0;
+  }
+
+  len = 0;
+
+  len += snprintf(buf + len, buf_cnt - len - 1, "Stats:\n" \
+                    "\trtskb_pool_empty: %ld\n" \
+                    "\trtskb_ringbuffer: %ld\n" \
+                    "\trtskb_ringbuffer_full: %ld\n" \
+                    "\trx_dropped: %ld\n" \
+                    "\trx_out: %ld\n" \
+                    "\ttx_in: %ld\n" \
+                    "\ttx_full: %ld\n" \
+                    "\ttx_pending: %ld\n",
+
+                    stats.rtskb_pool_empty,
+                    stats.rtskb_ringbuffer,
+                    stats.rtskb_ringbuffer_full,
+                    stats.rx_dropped,
+                    stats.rx_out,
+                    stats.tx_in,
+                    stats.tx_full,
+                    stats.tx_pending);
+
+#ifdef CONFIG_RTNET_CHECKED
+  len += snprintf(buf + len, buf_cnt - len - 1, "rtskb pool_balance: %d\n", rtskb_pool.pool_balance);
+#endif
+
+  *start = s_buf + offset;
+  *eof = (len >= offset) ? 0 : 1;
+  return eof ? (len - offset) : 0;
+}
+
 /* ***********************************************************************
  * Returns the next pointer from the ringbuffer or zero if nothing is
  * available
@@ -166,7 +235,7 @@ static void *write_to_ringbuffer(skb_exch_ringbuffer_t *pRing, void *p)
 /* ************************************************************************
  * net_device specific stuff:
  * ************************************************************************ */
-static struct net_device dev_rtnetproxy;
+static struct net_device* dev_rtnetproxy;
 
 static int rtnetproxy_xmit(struct sk_buff *skb, struct net_device *dev);
 
@@ -180,14 +249,18 @@ static int rtnetproxy_xmit(struct sk_buff *skb, struct net_device *dev);
 
 /* ************************************************************************
  * This functions runs in rtai context.
+ *
+ * Linux->RTnet
+ *
+ * TX'ed rtskb's are to be freed by the low-level driver.
+ *
  * It is called from rtnetproxy_transmit_thread whenever there is frame to
  * sent out. Copies the standard linux sk_buff buffer to a rtnet buffer and
  * sends it out using rtnet functions.
  * ************************************************************************ */
 static inline void send_data_out(struct sk_buff *skb)
 {
-
-    struct rtskb        *rtskb;
+    struct rtskb* rtskb = NULL;
 #ifndef CONFIG_RTNET_ADDON_PROXY_ARP
     struct dest_route   rt;
     int rc;
@@ -203,14 +276,14 @@ static inline void send_data_out(struct sk_buff *skb)
                                   * It represents the ethernet frame on the line and
                                   * thus no spaces are allowed! */
 
-    struct skb_data_format *pData;
+    struct skb_data_format* pData = NULL;
+
+    if(skb == NULL) return;
 
     /* Copy the data from the standard sk_buff to the realtime sk_buff:
      * Both have the same length. */
     rtskb = alloc_rtskb(skb->len, &rtskb_pool);
-    if (NULL == rtskb) {
-        return;
-    }
+    if(rtskb == NULL) return;
 
     memcpy(rtskb->data, skb->data, skb->len);
     rtskb->len = skb->len;
@@ -225,6 +298,8 @@ static inline void send_data_out(struct sk_buff *skb)
     /* Call the actual transmit function */
     rtdev_xmit_proxy(rtskb);
 
+    rtskb = NULL;
+
     rtdev_dereference(rtnetproxy_rtdev);
 
 #else /* !CONFIG_RTNET_ADDON_PROXY_ARP */
@@ -239,8 +314,7 @@ static inline void send_data_out(struct sk_buff *skb)
         /* check if IP source address fits */
         if (rtdev->local_ip != pData->ip_src) {
             rtdev_dereference(rtdev);
-            kfree_rtskb(rtskb);
-            return;
+            goto out;
         }
 
         rtskb->rtdev = rtdev;
@@ -255,20 +329,27 @@ static inline void send_data_out(struct sk_buff *skb)
 
         /* The rtskb is freed somewhere deep in the driver...
          * No need to do it here. */
+        rtskb = NULL; // XXX
 
         rtdev_dereference(rtdev);
     }
     else
     {
         /* Routing failed => Free rtskb here... */
-        kfree_rtskb(rtskb);
+        goto out;
     }
-
 #endif /* CONFIG_RTNET_ADDON_PROXY_ARP */
+
+  out:
+    if(rtskb != NULL)
+        kfree_rtskb(rtskb);
 }
 
 /* ************************************************************************
  * This is a RTAI thread. It will be activated (resumed) by the
+ *
+ * Linux->RTnet
+ *
  * functions "rtnetproxy_xmit" or "rtnetproxy_kernel_recv" (in linux context)
  * whenever new frames have to be sent out or if the
  * "used" rtskb ringbuffer is full.
@@ -280,17 +361,19 @@ static void rtnetproxy_transmit_thread(void *arg)
     while (1)
     {
         /* Free all "used" rtskbs in ringbuffer */
-        while ((del=read_from_ringbuffer(&ring_rtskb_kernel_rtnet)) != 0)	{
+        while ((del=read_from_ringbuffer(&ring_rtskb_kernel_rtnet)) != 0) {
             kfree_rtskb(del);
-    }
+        }
 
         /* Send out all frames in the ringbuffer that have not been sent yet */
         while ((skb = read_from_ringbuffer(&ring_skb_kernel_rtnet)) != 0)
         {
             send_data_out(skb);
+            stats.tx_pending--;
             /* Place the "used" skb in the ringbuffer back to kernel */
             write_to_ringbuffer(&ring_skb_rtnet_kernel, skb);
         }
+
         /* Will be activated with next frame to send... */
         rtdm_sem_down(&rtnetproxy_sem);
     }
@@ -305,8 +388,12 @@ static void rtnetproxy_transmit_thread(void *arg)
  * ************************************************************************ */
 static int rtnetproxy_xmit(struct sk_buff *skb, struct net_device *dev)
 {
+    int ret = 0;
+
+    stats.tx_in++;
     if (write_to_ringbuffer(&ring_skb_kernel_rtnet, skb))
     {
+        stats.tx_pending++;
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
         dev->stats.tx_packets++;
         dev->stats.tx_bytes+=skb->len;
@@ -314,14 +401,17 @@ static int rtnetproxy_xmit(struct sk_buff *skb, struct net_device *dev)
     }
     else
     {
+        stats.tx_full++;
         /* No space in the ringbuffer... */
         printk("rtnetproxy_xmit - no space in queue\n");
-        dev_kfree_skb(skb);  /* Free the standard skb. */
+        /////dev_kfree_skb(skb);  /* Free the standard skb. */
+        ret = NETDEV_TX_BUSY;
     }
 
     /* Signal rtnet that there are packets waiting to be processed...
      * */
-    rtdm_sem_up(&rtnetproxy_sem);
+    if(ret != 0)
+        rtdm_sem_up(&rtnetproxy_sem);
 
     /* Delete all "used" skbs that already have been processed... */
     {
@@ -331,7 +421,8 @@ static int rtnetproxy_xmit(struct sk_buff *skb, struct net_device *dev)
             dev_kfree_skb(del_skb);  /* Free the standard skb. */
         }
     }
-    return 0;
+
+    return ret;
 }
 
 
@@ -345,24 +436,29 @@ static int rtnetproxy_xmit(struct sk_buff *skb, struct net_device *dev)
 /* ************************************************************************
  * This function runs in real-time context.
  *
+ * RTnet->Linux
+ *
  * It is called from inside rtnet whenever a packet has been received that
  * has to be processed by rtnetproxy.
  * ************************************************************************ */
 static void rtnetproxy_recv(struct rtskb *rtskb)
 {
     /* Acquire rtskb (JK) */
-    if (rtskb_acquire(rtskb, &rtskb_pool) != 0) {
+    if (rtskb_acquire(rtskb, &rtskb_pool) != 0) { // steal rtskb from RTnet pool into our pool
+        stats.rtskb_pool_empty++;
         rtdm_printk("rtnetproxy_recv: No free rtskb in pool\n");
         kfree_rtskb(rtskb);
     }
     /* Place the rtskb in the ringbuffer: */
-    else if (write_to_ringbuffer(&ring_rtskb_rtnet_kernel, rtskb))
+    else if (write_to_ringbuffer(&ring_rtskb_rtnet_kernel, rtskb)) // rtnetproxy_recv
     {
+        stats.rtskb_ringbuffer++;
         /* Switch over to kernel context: */
         rtdm_nrtsig_pend(&rtnetproxy_signal);
     }
     else
     {
+        stats.rtskb_ringbuffer_full++;
         /* No space in ringbuffer => Free rtskb here... */
         rtdm_printk("rtnetproxy_recv: No space in queue\n");
         kfree_rtskb(rtskb);
@@ -372,13 +468,16 @@ static void rtnetproxy_recv(struct rtskb *rtskb)
 
 /* ************************************************************************
  * This function runs in kernel mode.
+ *
+ * RTnet->Linux
+ *
  * It is activated from rtnetproxy_signal_handler whenever rtnet received a
  * frame to be processed by rtnetproxy.
  * ************************************************************************ */
 static inline void rtnetproxy_kernel_recv(struct rtskb *rtskb)
 {
     struct sk_buff *skb;
-    struct net_device *dev = &dev_rtnetproxy;
+    struct net_device *dev = dev_rtnetproxy;
 
     int header_len = rtskb->rtdev->hard_header_len;
     int len        = rtskb->len + header_len;
@@ -389,7 +488,6 @@ static inline void rtnetproxy_kernel_recv(struct rtskb *rtskb)
 
     memcpy(skb_put(skb, len), rtskb->data-header_len, len);
 
-
     /* Set some relevant entries in the skb: */
     skb->protocol=eth_type_trans(skb,dev);
     skb->dev=dev;
@@ -409,12 +507,16 @@ static inline void rtnetproxy_kernel_recv(struct rtskb *rtskb)
     dev->stats.rx_packets++;
 #endif
 
-    netif_rx(skb);  /* pass it to the received stuff */
-
+    if(netif_rx(skb) == NET_RX_SUCCESS)  /* pass it to the received stuff */
+         stats.rx_out++;
+    else stats.rx_dropped++;
 }
 
 /* ************************************************************************
  * This function runs in kernel mode.
+ *
+ * RTnet->Linux
+ *
  * It is activated from rtnetproxy_recv whenever rtnet received a frame to
  * be processed by rtnetproxy.
  * ************************************************************************ */
@@ -422,8 +524,9 @@ static void rtnetproxy_signal_handler(rtdm_nrtsig_t nrtsig, void *arg)
 {
     struct rtskb *rtskb;
 
-    while ( (rtskb = read_from_ringbuffer(&ring_rtskb_rtnet_kernel)) != 0)
+    while ( (rtskb = read_from_ringbuffer(&ring_rtskb_rtnet_kernel)) != 0) // rtnetproxy_signal_handler
     {
+        stats.rtskb_ringbuffer--;
         rtnetproxy_kernel_recv(rtskb);
         /* Place "used" rtskb in backqueue... */
         while (0 == write_to_ringbuffer(&ring_rtskb_kernel_rtnet, rtskb)) {
@@ -490,6 +593,15 @@ static int __init rtnetproxy_init_module(void)
 {
     int err;
 
+    procFileEntry = create_proc_read_entry(
+                        "rtnetproxy_stats",
+                        S_IFREG | S_IRUGO,
+                        NULL,   /* base entry */
+                        procfile_read,  /* read operation */
+                        NULL    /* data */
+                  );
+    if(procFileEntry == NULL) return -ENOMEM;
+
 #ifdef CONFIG_RTNET_ADDON_PROXY_ARP
     if ((rtnetproxy_rtdev = rtdev_get_by_name(rtdev_attach)) == NULL) {
 	printk("Couldn't attach to %s\n", rtdev_attach);
@@ -505,12 +617,19 @@ static int __init rtnetproxy_init_module(void)
         return -ENOMEM;
     }
 
+    /* alloc_etherdev ensures aligned and zeroed private structures */
+    dev_rtnetproxy = alloc_etherdev(sizeof(struct rtnetproxy_priv));
+    if (!dev_rtnetproxy) {
+        printk (KERN_ERR "%s: ether device alloc failed, aborting\n", __FUNCTION__);
+        return -ENOMEM;
+    }
+
 #ifdef HAVE_NET_DEVICE_OPS
-    dev_rtnetproxy.netdev_ops = &rtnetproxy_netdev_ops;
+    dev_rtnetproxy->netdev_ops = &rtnetproxy_netdev_ops;
 #else /* !HAVE_NET_DEVICE_OPS */
-    dev_rtnetproxy.init = rtnetproxy_init;
-    dev_rtnetproxy.hard_start_xmit = rtnetproxy_xmit;
-    dev_rtnetproxy.set_multicast_list = set_multicast_list;
+    dev_rtnetproxy->init = rtnetproxy_init;
+    dev_rtnetproxy->hard_start_xmit = rtnetproxy_xmit;
+    dev_rtnetproxy->set_multicast_list = set_multicast_list;
 #ifdef CONFIG_NET_FASTROUTE
     dev->accept_fastpath = rtnetproxy_accept_fastpath;
 #endif
@@ -519,15 +638,22 @@ static int __init rtnetproxy_init_module(void)
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
     SET_MODULE_OWNER(&dev_rtnetproxy);
 #endif
+  
+    {
+        struct rtnetproxy_priv* priv = netdev_priv(dev_rtnetproxy);
+        if(priv) {
+            priv->dev = dev_rtnetproxy;
+        }
+    }
 
     /* Define the name for this unit */
-    err=dev_alloc_name(&dev_rtnetproxy,"rtproxy");
-
+    err=dev_alloc_name(dev_rtnetproxy, "rtproxy");
     if(err<0) {
         rtskb_pool_release(&rtskb_pool);
         return err;
     }
-    err = register_netdev(&dev_rtnetproxy);
+
+    err = register_netdev(dev_rtnetproxy);
     if (err<0) {
         rtskb_pool_release(&rtskb_pool);
         return err;
@@ -551,7 +677,7 @@ static int __init rtnetproxy_init_module(void)
     /* Register with RTnet */
     rt_ip_fallback_handler = rtnetproxy_recv;
 
-    printk("rtnetproxy installed as \"%s\"\n", dev_rtnetproxy.name);
+    printk("rtnetproxy installed as \"%s\"\n", dev_rtnetproxy->name);
 
     return 0;
 }
@@ -586,16 +712,20 @@ static void __exit rtnetproxy_cleanup_module(void)
         {
             kfree_rtskb(del); // Although this is kernel mode, freeing should work...
         }
-        while ((del=read_from_ringbuffer(&ring_rtskb_rtnet_kernel))!=0)
+        while ((del=read_from_ringbuffer(&ring_rtskb_rtnet_kernel))!=0) // rtnetproxy_cleanup_module
         {
             kfree_rtskb(del); // Although this is kernel mode, freeing should work...
         }
     }
 
     /* Unregister the net device: */
-    unregister_netdev(&dev_rtnetproxy);
+    unregister_netdev(dev_rtnetproxy);
+
+    free_netdev(dev_rtnetproxy);
 
     rtskb_pool_release(&rtskb_pool);
+
+    remove_proc_entry(procFileEntry->name, procFileEntry->subdir);
 }
 
 module_init(rtnetproxy_init_module);
