Hallo,

I have written this small patch for RTnet during a research project, so if anyone is interested, here it is.

It allows to register multiple packet handlers for a single protocol and to have separate handlers depending on the interface. For this reason I also added shared SKB support (inspiration by the newer kernels).

The changes should be transparent for most code, though I didn't test it with the more advanced features of RTNet (e.g. TDMA).


Best regards, Petr Grillinger
diff -urNp -x '\.*' -x '*.[ao]' rtnet-0.8.0/stack/include/rtskb.h 
rtnet-0.8.0-pg/stack/include/rtskb.h
--- rtnet-0.8.0/stack/include/rtskb.h   2004-12-09 10:09:38.000000000 +0100
+++ rtnet-0.8.0-pg/stack/include/rtskb.h        2004-12-28 10:17:31.000000000 
+0100
@@ -28,6 +28,7 @@
 #ifdef __KERNEL__
 
 #include <linux/skbuff.h>
+#include <asm/atomic.h>
 
 #include <rtnet_internal.h>
 
@@ -197,6 +199,7 @@ struct rtskb {
         unsigned char   *raw;
     } mac;
 
+    atomic_t            users;   // number of active users of shared SKB 
     unsigned short      protocol;
     unsigned char       pkt_type;
 
@@ -262,7 +265,7 @@ struct rtskb_prio_queue {
 #define DEFAULT_SOCKET_RTSKBS       16      /* default number of rtskb's in 
socket pools */
 
 #define ALIGN_RTSKB_STRUCT_LEN      SKB_DATA_ALIGN(sizeof(struct rtskb))
-#define RTSKB_SIZE                  1544    /* maximum needed by pcnet32-rt */
+#define RTSKB_SIZE                  (1544 + sizeof(atomic_t))    /* maximum 
needed by pcnet32-rt */
 
 extern unsigned int socket_rtskbs;      /* default number of rtskb's in socket 
pools */
 
diff -urNp -x '\.*' -x '*.[ao]' rtnet-0.8.0/stack/include/stack_mgr.h 
rtnet-0.8.0-pg/stack/include/stack_mgr.h
--- rtnet-0.8.0/stack/include/stack_mgr.h       2004-10-28 18:05:41.000000000 
+0200
+++ rtnet-0.8.0-pg/stack/include/stack_mgr.h    2004-12-27 11:50:33.000000000 
+0100
@@ -40,6 +40,8 @@ struct rtpacket_type {
     int            (*handler)(struct rtskb *, struct rtpacket_type *);
     int            (*err_handler)(struct rtskb *, struct rtnet_device *,
                                   struct rtpacket_type *);
+    int            ifindex;
+    struct rtpacket_type *next;
 };
 
 
diff -urNp -x '\.*' -x '*.[ao]' rtnet-0.8.0/stack/packet/af_packet.c 
rtnet-0.8.0-pg/stack/packet/af_packet.c
--- rtnet-0.8.0/stack/packet/af_packet.c        2004-10-28 18:05:41.000000000 
+0200
+++ rtnet-0.8.0-pg/stack/packet/af_packet.c     2004-12-28 10:20:21.000000000 
+0100
@@ -36,16 +36,15 @@ int rt_packet_rcv(struct rtskb *skb, str
 {
     struct rtsocket *sock = (struct rtsocket *)(((u8 *)pt) -
                                 ((u8 *)&((struct rtsocket *)0)->prot.packet));
-    int             ifindex = sock->prot.packet.ifindex;
     void            (*callback_func)(struct rtdm_dev_context *, void *);
     void            *callback_arg;
     unsigned long   flags;
 
 
-    if (((ifindex != 0) && (ifindex != skb->rtdev->ifindex)) ||
-        (rtskb_acquire(skb, &sock->skb_pool) != 0))
+    if (rtskb_acquire(skb, &sock->skb_pool) != 0) {
         kfree_rtskb(skb);
-    else {
+       rtos_print("Cannot acquire rtskb\n");
+    } else {
         rtdev_reference(skb->rtdev);
         rtskb_queue_tail(&sock->incoming, skb);
         rtos_event_sem_signal(&sock->wakeup_event);
@@ -91,6 +90,7 @@ int rt_packet_bind(struct rtsocket *sock
     }
 
     pt->type = new_type;
+    pt->ifindex = sll->sll_ifindex;
     sock->prot.packet.ifindex = sll->sll_ifindex;
 
     /* if protocol is non-zero, register the packet type */
diff -urNp -x '\.*' -x '*.[ao]' rtnet-0.8.0/stack/rtskb.c 
rtnet-0.8.0-pg/stack/rtskb.c
--- rtnet-0.8.0/stack/rtskb.c   2004-12-09 10:09:39.000000000 +0100
+++ rtnet-0.8.0-pg/stack/rtskb.c        2004-12-27 11:50:33.000000000 +0100
@@ -189,6 +189,7 @@ struct rtskb *alloc_rtskb(unsigned int s
     skb->len = 0;
     skb->pkt_type = PACKET_HOST;
     skb->xmit_stamp = NULL;
+    atomic_set(&skb->users, 1);
 
 #ifdef CONFIG_RTNET_RTCAP
     skb->cap_flags = 0;
@@ -215,6 +216,11 @@ void kfree_rtskb(struct rtskb *skb)
 
     RTNET_ASSERT(skb != NULL, return;);
     RTNET_ASSERT(skb->pool != NULL, return;);
+    RTNET_ASSERT(atomic_read(&skb->users) > 0, return;);
+    
+    /* Do not free SKB with active users */
+    if (!atomic_dec_and_test(&skb->users))
+        return;
 
 #ifdef CONFIG_RTNET_RTCAP
     next_skb  = skb;
diff -urNp -x '\.*' -x '*.[ao]' rtnet-0.8.0/stack/stack_mgr.c 
rtnet-0.8.0-pg/stack/stack_mgr.c
--- rtnet-0.8.0/stack/stack_mgr.c       2004-10-28 18:05:41.000000000 +0200
+++ rtnet-0.8.0-pg/stack/stack_mgr.c    2004-12-27 13:18:42.000000000 +0100
@@ -46,20 +46,12 @@ int rtdev_add_pack(struct rtpacket_type 
 
     rtos_spin_lock_irqsave(&rt_packets_lock, flags);
 
-    if (rt_packets[hash] == NULL) {
-        rt_packets[hash] = pt;
-
-        pt->refcount = 0;
-
-        rtos_spin_unlock_irqrestore(&rt_packets_lock, flags);
-
-        return 0;
-    }
-    else {
-        rtos_spin_unlock_irqrestore(&rt_packets_lock, flags);
-
-        return -EADDRNOTAVAIL;
-    }
+    pt->next = rt_packets[hash];
+    rt_packets[hash] = pt;
+    pt->refcount = 0;
+ 
+    rtos_spin_unlock_irqrestore(&rt_packets_lock, flags);
+    return 0;
 }
 
 
@@ -84,22 +76,22 @@ int rtdev_remove_pack(struct rtpacket_ty
 
     rtos_spin_lock_irqsave(&rt_packets_lock, flags);
 
-    if ((rt_packets[hash] != NULL) &&
-        (rt_packets[hash]->type == pt->type)) {
-        rt_packets[hash] = NULL;
-
-        if (pt->refcount > 0)
-            ret = -EAGAIN;
-
-        rtos_spin_unlock_irqrestore(&rt_packets_lock, flags);
-
-        return ret;
+    struct rtpacket_type **rtp = &(rt_packets[hash]);
+    
+    while ((*rtp) != NULL) {
+        if (*rtp == pt) {
+           *rtp = pt->next;
+           if (pt->refcount > 0)
+                ret = -EAGAIN;
+           goto ende; 
+        }
+        rtp = &((*rtp)->next);
     }
-    else {
-        rtos_spin_unlock_irqrestore(&rt_packets_lock, flags);
+    ret = -ENOENT;
 
-        return -ENOENT;
-    }
+ende:
+    rtos_spin_unlock_irqrestore(&rt_packets_lock, flags);
+    return ret;
 }
 
 
@@ -185,28 +177,38 @@ static void do_stacktask(int mgr_id)
             hash = ntohs(skb->protocol) & (MAX_RT_PROTOCOLS-1);
 
             rtos_spin_lock_irqsave(&rt_packets_lock, flags);
-
             pt = rt_packets[hash];
 
-            if ((pt != NULL) && (pt->type == skb->protocol)) {
-                pt->refcount++;
-                rtos_spin_unlock_irqrestore(&rt_packets_lock, flags);
-
-                pt->handler(skb, pt);
-
-                rtos_spin_lock_irqsave(&rt_packets_lock, flags);
-                pt->refcount--;
-                rtos_spin_unlock_irqrestore(&rt_packets_lock, flags);
-            } else {
-                rtos_spin_unlock_irqrestore(&rt_packets_lock, flags);
-
-                /* don't warn if running in promiscuous mode (RTcap...?) */
-                if ((rtdev->flags & IFF_PROMISC) == 0)
-                    rtos_print("RTnet: unknown layer-3 protocol\n");
-
-                kfree_rtskb(skb);
+            int proto_cnt = 0, 
+                if_cnt = 0;
+            for ( ; pt; pt = pt->next) {
+                if (pt->type == skb->protocol) {
+                    if (!pt->ifindex || pt->ifindex == skb->rtdev->ifindex) { 
+                        pt->refcount++;
+                        rtos_spin_unlock_irqrestore(&rt_packets_lock, flags);
+
+                        atomic_inc(&skb->users);
+                        pt->handler(skb, pt);
+
+                        rtos_spin_lock_irqsave(&rt_packets_lock, flags);
+                        pt->refcount--;
+                        if_cnt++;
+                    } 
+                    proto_cnt++;
+                }
             }
-
+            rtos_spin_unlock_irqrestore(&rt_packets_lock, flags);
+            
+            /* don't warn if running in promiscuous mode (RTcap...?) */
+            if ((rtdev->flags & IFF_PROMISC) == 0) {
+                if (proto_cnt == 0)
+                    rtos_print("RTnet: missing handler for protocol 0x%04x\n", 
+                            ntohs(skb->protocol));
+                else if (if_cnt == 0)
+                    rtos_print("RTnet: missing handler for protocol 0x%04x, 
interface %d\n", 
+                            ntohs(skb->protocol), skb->rtdev->ifindex);
+            }
+            kfree_rtskb(skb);
             rtdev_dereference(rtdev);
         }
     }

Reply via email to