All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/16] multicast, VLAN support for RTnet
@ 2019-03-21 17:13 Philippe Gerum
  2019-03-21 17:13 ` [PATCH 01/16] net/stack: plan for merging private device flags with netdev_priv_flags Philippe Gerum
                   ` (15 more replies)
  0 siblings, 16 replies; 19+ messages in thread
From: Philippe Gerum @ 2019-03-21 17:13 UTC (permalink / raw)
  To: xenomai

Some time ago, Gilles Chanteperdrix added multicast and VLAN support
to the original RTnet code base (0.9.13). iXblue, the company who owns
such work, has released this code, with permission to contribute it to
the Xenomai project. Many thanks to Stéphane Belot at iXblue for
making it possible.

Apart from marginal changes to cope with a few API differences between
the original RTnet implementation and Xenomai's, the content of this
series is almost entirely Gilles's work.

=====================================================================
NOTE: this code applies on top of the reformating patch sent earlier.
=====================================================================

Gilles Chanteperdrix (16):
  net/stack: plan for merging private device flags with
    netdev_priv_flags
  net/stack: add multicast support
  utils/net: rtifconfig: display device name untruncated
  net/stack: add support for VLAN filtering
  utils/net: add VLAN filter configuration tool
  net/udp: allow retrieving irq timestamp with SIOCGSTAMP ioctl
  net/udp sendmsg: do not return an error if dest addr is null
  net/stack: rtskb: increase buffer size
  net/stack: manager: ratelimit printk when dropping buffers
  net/ipv4: icmp: forward unused packets to proxy
  net/drivers: e1000e: enable multicast
  net/drivers: e1000e: enable VLAN filtering
  net/drivers: e1000e: add netdevice stats
  net/drivers: igb: enable multicast
  net/drivers: igb: enable VLAN filtering
  demo/net: add rtnet tests

 configure.ac                                  |   1 +
 demo/Makefile.am                              |   2 +-
 demo/net/Makefile.am                          |  78 ++
 demo/net/mcast-receiver.c                     | 204 +++++
 demo/net/mcast-sender.c                       | 151 ++++
 demo/net/raw-ethernet.c                       | 100 +++
 demo/net/rtt-mcast-measure.c                  | 210 +++++
 demo/net/rtt-mcast-responder.c                | 109 +++
 demo/net/rtt-responder.c                      | 193 +++++
 demo/net/rtt-sender.c                         | 341 ++++++++
 demo/net/rttcp-client.c                       | 212 +++++
 demo/net/rttcp-server.c                       | 181 +++++
 demo/net/udp-send.c                           | 136 ++++
 kernel/drivers/net/addons/cap.c               |  47 +-
 kernel/drivers/net/drivers/e1000e/e1000.h     |   6 +-
 kernel/drivers/net/drivers/e1000e/hw.h        |   2 +-
 kernel/drivers/net/drivers/e1000e/lib.c       |   7 +-
 kernel/drivers/net/drivers/e1000e/netdev.c    | 270 ++++++-
 kernel/drivers/net/drivers/igb/e1000_mac.c    |   6 +-
 kernel/drivers/net/drivers/igb/e1000_mac.h    |   2 +-
 kernel/drivers/net/drivers/igb/igb_main.c     |  53 +-
 kernel/drivers/net/stack/Kconfig              |   7 +
 kernel/drivers/net/stack/Makefile             |   2 +
 kernel/drivers/net/stack/include/ipv4/arp.h   |   3 +
 kernel/drivers/net/stack/include/ipv4/igmp.h  | 102 +++
 .../drivers/net/stack/include/ipv4/protocol.h |   1 +
 kernel/drivers/net/stack/include/rtdev.h      |  45 +-
 kernel/drivers/net/stack/include/rtif_vlan.h  | 105 +++
 kernel/drivers/net/stack/include/rtnet_port.h |   6 +-
 .../drivers/net/stack/include/rtnet_socket.h  |   6 +
 kernel/drivers/net/stack/include/rtskb.h      |   4 +-
 kernel/drivers/net/stack/include/rtvlan.h     |  25 +
 kernel/drivers/net/stack/ipv4/Kconfig         |   7 +
 kernel/drivers/net/stack/ipv4/Makefile        |   1 +
 kernel/drivers/net/stack/ipv4/af_inet.c       |   5 +
 kernel/drivers/net/stack/ipv4/arp.c           |  26 +
 kernel/drivers/net/stack/ipv4/icmp.c          |  18 +-
 kernel/drivers/net/stack/ipv4/igmp.c          | 616 +++++++++++++++
 kernel/drivers/net/stack/ipv4/ip_output.c     |  13 +-
 kernel/drivers/net/stack/ipv4/ip_sock.c       |  51 +-
 kernel/drivers/net/stack/ipv4/protocol.c      |  17 +
 kernel/drivers/net/stack/ipv4/tcp/tcp.c       |   2 +-
 kernel/drivers/net/stack/ipv4/udp/udp.c       |  55 +-
 kernel/drivers/net/stack/rtdev.c              | 214 ++++++
 kernel/drivers/net/stack/rtnet_chrdev.c       |   7 +-
 kernel/drivers/net/stack/rtnet_module.c       |   5 +
 kernel/drivers/net/stack/socket.c             |  16 +-
 kernel/drivers/net/stack/stack_mgr.c          |   2 +-
 kernel/drivers/net/stack/vlan.c               | 725 ++++++++++++++++++
 utils/net/Makefile.am                         |   1 +
 utils/net/rtifconfig.c                        |   2 +-
 utils/net/rtvconfig.c                         | 257 +++++++
 52 files changed, 4551 insertions(+), 106 deletions(-)
 create mode 100644 demo/net/Makefile.am
 create mode 100644 demo/net/mcast-receiver.c
 create mode 100644 demo/net/mcast-sender.c
 create mode 100644 demo/net/raw-ethernet.c
 create mode 100644 demo/net/rtt-mcast-measure.c
 create mode 100644 demo/net/rtt-mcast-responder.c
 create mode 100644 demo/net/rtt-responder.c
 create mode 100644 demo/net/rtt-sender.c
 create mode 100644 demo/net/rttcp-client.c
 create mode 100644 demo/net/rttcp-server.c
 create mode 100644 demo/net/udp-send.c
 create mode 100644 kernel/drivers/net/stack/include/ipv4/igmp.h
 create mode 100644 kernel/drivers/net/stack/include/rtif_vlan.h
 create mode 100644 kernel/drivers/net/stack/include/rtvlan.h
 create mode 100644 kernel/drivers/net/stack/ipv4/igmp.c
 create mode 100644 kernel/drivers/net/stack/vlan.c
 create mode 100644 utils/net/rtvconfig.c

-- 
2.20.1



^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH 01/16] net/stack: plan for merging private device flags with netdev_priv_flags
  2019-03-21 17:13 [PATCH 00/16] multicast, VLAN support for RTnet Philippe Gerum
@ 2019-03-21 17:13 ` Philippe Gerum
  2019-03-21 17:13 ` [PATCH 02/16] net/stack: add multicast support Philippe Gerum
                   ` (14 subsequent siblings)
  15 siblings, 0 replies; 19+ messages in thread
From: Philippe Gerum @ 2019-03-21 17:13 UTC (permalink / raw)
  To: xenomai; +Cc: Gilles Chanteperdrix, Philippe Gerum

From: Gilles Chanteperdrix <gilles.chanteperdrix@xenomai.org>

We need to merge regular netdev_priv_flags with our own private device
flags for the upcoming VLAN, multicast support. Pick non-conflicting
bit positions.

Signed-off-by: Philippe Gerum <rpm@xenomai.org>
---
 kernel/drivers/net/stack/include/rtdev.h | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/kernel/drivers/net/stack/include/rtdev.h b/kernel/drivers/net/stack/include/rtdev.h
index 8f8fa16b9..1102a839d 100644
--- a/kernel/drivers/net/stack/include/rtdev.h
+++ b/kernel/drivers/net/stack/include/rtdev.h
@@ -38,8 +38,13 @@
 
 #define RTDEV_VERS_2_0                  0x0200
 
-#define PRIV_FLAG_UP                    0
-#define PRIV_FLAG_ADDING_ROUTE          1
+/*
+ * We need to merge regular netdev_priv_flags with our own private
+ * device flags for VLAN, multicast support. Pick non-conflicting bit
+ * positions.
+ */
+#define PRIV_FLAG_UP                    30
+#define PRIV_FLAG_ADDING_ROUTE          31
 
 #ifndef NETIF_F_LLTX
 #define NETIF_F_LLTX                    4096
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH 02/16] net/stack: add multicast support
  2019-03-21 17:13 [PATCH 00/16] multicast, VLAN support for RTnet Philippe Gerum
  2019-03-21 17:13 ` [PATCH 01/16] net/stack: plan for merging private device flags with netdev_priv_flags Philippe Gerum
@ 2019-03-21 17:13 ` Philippe Gerum
  2019-03-21 17:13 ` [PATCH 03/16] utils/net: rtifconfig: display device name untruncated Philippe Gerum
                   ` (13 subsequent siblings)
  15 siblings, 0 replies; 19+ messages in thread
From: Philippe Gerum @ 2019-03-21 17:13 UTC (permalink / raw)
  To: xenomai; +Cc: Gilles Chanteperdrix, Philippe Gerum

From: Gilles Chanteperdrix <gilles.chanteperdrix@xenomai.org>

Signed-off-by: Philippe Gerum <rpm@xenomai.org>
---
 kernel/drivers/net/stack/include/ipv4/arp.h   |   3 +
 kernel/drivers/net/stack/include/ipv4/igmp.h  | 102 +++
 .../drivers/net/stack/include/ipv4/protocol.h |   1 +
 kernel/drivers/net/stack/include/rtdev.h      |  17 +
 .../drivers/net/stack/include/rtnet_socket.h  |   4 +
 kernel/drivers/net/stack/include/rtskb.h      |   1 +
 kernel/drivers/net/stack/ipv4/Kconfig         |   7 +
 kernel/drivers/net/stack/ipv4/Makefile        |   1 +
 kernel/drivers/net/stack/ipv4/af_inet.c       |   5 +
 kernel/drivers/net/stack/ipv4/arp.c           |  26 +
 kernel/drivers/net/stack/ipv4/igmp.c          | 616 ++++++++++++++++++
 kernel/drivers/net/stack/ipv4/ip_output.c     |  13 +-
 kernel/drivers/net/stack/ipv4/ip_sock.c       |  51 +-
 kernel/drivers/net/stack/ipv4/protocol.c      |  17 +
 kernel/drivers/net/stack/ipv4/tcp/tcp.c       |   2 +-
 kernel/drivers/net/stack/ipv4/udp/udp.c       |  43 +-
 kernel/drivers/net/stack/rtdev.c              | 202 ++++++
 17 files changed, 1101 insertions(+), 10 deletions(-)
 create mode 100644 kernel/drivers/net/stack/include/ipv4/igmp.h
 create mode 100644 kernel/drivers/net/stack/ipv4/igmp.c

diff --git a/kernel/drivers/net/stack/include/ipv4/arp.h b/kernel/drivers/net/stack/include/ipv4/arp.h
index becffb6fa..4c36b9070 100644
--- a/kernel/drivers/net/stack/include/ipv4/arp.h
+++ b/kernel/drivers/net/stack/include/ipv4/arp.h
@@ -49,4 +49,7 @@ static inline void rt_arp_solicit(struct rtnet_device *rtdev, u32 target)
 void __init rt_arp_init(void);
 void rt_arp_release(void);
 
+int rt_arp_mc_map(u32 addr, u8 *haddr,
+		  struct rtnet_device *dev, int dir);
+
 #endif /* __RTNET_ARP_H_ */
diff --git a/kernel/drivers/net/stack/include/ipv4/igmp.h b/kernel/drivers/net/stack/include/ipv4/igmp.h
new file mode 100644
index 000000000..a44e09041
--- /dev/null
+++ b/kernel/drivers/net/stack/include/ipv4/igmp.h
@@ -0,0 +1,102 @@
+/*
+ *  include/ipv4/igmp.h - Internet Group Management Protocol  [IGMP]
+ *
+ *      Adapted from linux/igmp.h to RTnet by:
+ *              Gilles Chanteperdrix <gilles.chanteperdrix@xenomai.org>
+ *	Original author:
+ *		Alan Cox <Alan.Cox@linux.org>
+ *
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License
+ *	as published by the Free Software Foundation; either version
+ *	2 of the License, or (at your option) any later version.
+ */
+
+#ifndef __RTNET_IGMP_H_
+#define __RTNET_IGMP_H_
+#include <asm/byteorder.h>
+#include <linux/init.h>
+#include <linux/kconfig.h>
+#include <linux/in.h>
+#include <rtnet_socket.h>
+
+struct igmphdr {
+	__u8 type;
+	__u8 code;		/* For newer IGMP */
+	__u16 csum;
+	__u32 group;
+};
+
+#define IGMP_HOST_MEMBERSHIP_QUERY	0x11	/* From RFC1112 */
+#define IGMP_HOST_MEMBERSHIP_REPORT	0x12	/* Ditto */
+#define IGMP_DVMRP			0x13	/* DVMRP routing */
+#define IGMP_PIM			0x14	/* PIM routing */
+#define IGMP_TRACE			0x15
+#define IGMP_HOST_NEW_MEMBERSHIP_REPORT 0x16	/* New version of 0x11 */
+#define IGMP_HOST_LEAVE_MESSAGE 	0x17
+
+#define IGMP_MTRACE_RESP		0x1e
+#define IGMP_MTRACE			0x1f
+
+#define IGMP_DELAYING_MEMBER		0x01
+#define IGMP_IDLE_MEMBER		0x02
+#define IGMP_LAZY_MEMBER		0x03
+#define IGMP_SLEEPING_MEMBER		0x04
+#define IGMP_AWAKENING_MEMBER		0x05
+
+#define IGMP_MINLEN			8
+
+#define IGMP_MAX_HOST_REPORT_DELAY	10	/* max delay for response to */
+						/* query (in seconds)   */
+
+#define IGMP_TIMER_SCALE		10	/* denotes that the igmphdr->timer field */
+						/* specifies time in 10th of seconds     */
+
+#define IGMP_AGE_THRESHOLD		400	/* If this host don't hear any IGMP V1  */
+						/* message in this period of time,      */
+						/* revert to IGMP v2 router.            */
+
+#define IGMP_ALL_HOSTS		htonl(0xE0000001L)
+#define IGMP_ALL_ROUTER 	htonl(0xE0000002L)
+#define IGMP_LOCAL_GROUP	htonl(0xE0000000L)
+#define IGMP_LOCAL_GROUP_MASK	htonl(0xFFFFFF00L)
+
+enum rtip_mc_state {
+	RTIP_MC_NON_MEMBER,
+	RTIP_MC_DELAYING_MEMBER,
+	RTIP_MC_IDLE_MEMBER,
+};
+
+struct rtip_mc_socklist {
+	struct rtip_mc_socklist	*next;
+	struct ip_mreq		multi;
+};
+
+struct rtip_mc_list {
+	struct rtnet_device	*interface;
+	u32			multiaddr;
+	struct rtip_mc_list	*next;
+	int			users;
+	enum rtip_mc_state	state;
+};
+
+static inline bool rtnet_in_multicast(u32 addr)
+{
+	return IS_ENABLED(CONFIG_XENO_DRIVERS_NET_RTIPV4_IGMP) &&
+		IN_MULTICAST(addr);
+}
+
+#ifdef CONFIG_XENO_DRIVERS_NET_RTIPV4_IGMP
+int rt_ip_mc_join_group(struct rtsocket *sk, struct ip_mreq *imr);
+int rt_ip_mc_leave_group(struct rtsocket *sk, struct ip_mreq *imr);
+void rt_ip_mc_drop_socket(struct rtsocket *sk);
+void rt_ip_mc_dec_group(struct rtnet_device *rtdev, u32 addr);
+void rt_ip_mc_inc_group(struct rtnet_device *rtdev, u32 addr);
+void rt_igmp_init(void);
+void rt_igmp_release(void);
+#else
+static inline void rt_igmp_init(void) { }
+static inline void rt_igmp_release(void) { }
+#endif
+
+#endif /* __RTNET_IGMP_H_ */
diff --git a/kernel/drivers/net/stack/include/ipv4/protocol.h b/kernel/drivers/net/stack/include/ipv4/protocol.h
index 499c31d9b..d1de325c4 100644
--- a/kernel/drivers/net/stack/include/ipv4/protocol.h
+++ b/kernel/drivers/net/stack/include/ipv4/protocol.h
@@ -50,5 +50,6 @@ extern struct rtinet_protocol *rt_inet_protocols[];
 extern void rt_inet_add_protocol(struct rtinet_protocol *prot);
 extern void rt_inet_del_protocol(struct rtinet_protocol *prot);
 extern int rt_inet_socket(struct rtdm_fd *fd, int protocol);
+extern int rt_inet_socket_cleanup(struct rtdm_fd *fd);
 
 #endif /* __RTNET_PROTOCOL_H_ */
diff --git a/kernel/drivers/net/stack/include/rtdev.h b/kernel/drivers/net/stack/include/rtdev.h
index 1102a839d..fe015c338 100644
--- a/kernel/drivers/net/stack/include/rtdev.h
+++ b/kernel/drivers/net/stack/include/rtdev.h
@@ -64,6 +64,14 @@ enum rtnet_link_state {
 #define RTNET_LINK_STATE_PRESENT (1 << __RTNET_LINK_STATE_PRESENT)
 #define RTNET_LINK_STATE_NOCARRIER (1 << __RTNET_LINK_STATE_NOCARRIER)
 
+struct rtdev_mc_list {
+    struct rtdev_mc_list    *next;
+    __u8                    dmi_addr[MAX_ADDR_LEN];
+    unsigned char           dmi_addrlen;
+    int                     dmi_users;
+    int                     dmi_gusers;
+};
+
 /***
  *  rtnet_device
  */
@@ -114,6 +122,8 @@ struct rtnet_device {
 
 	int promiscuity;
 	int allmulti;
+	struct rtdev_mc_list *mc_list;
+	int mc_count;
 
 	__u32 local_ip;		/* IP address in network order  */
 	__u32 broadcast_ip;	/* broadcast IP in network order */
@@ -142,6 +152,7 @@ struct rtnet_device {
 	int (*rebuild_header) (struct rtskb *);
 	int (*hard_start_xmit) (struct rtskb * skb, struct rtnet_device * dev);
 	int (*hw_reset) (struct rtnet_device * rtdev);
+	void (*set_multicast_list) (struct rtnet_device *rtdev);
 
 	/* Transmission hook, managed by the stack core, RTcap, and RTmac
 	 *
@@ -247,6 +258,12 @@ void rtdev_unmap_rtskb(struct rtskb *skb);
 
 struct rtskb *rtnetdev_alloc_rtskb(struct rtnet_device *dev, unsigned int size);
 
+struct rtnet_device *rt_ip_dev_find(u32 addr);
+void rt_dev_mc_upload(struct rtnet_device *dev);
+int rt_dev_mc_delete(struct rtnet_device *dev, void *addr, int alen, int all);
+int rt_dev_mc_add(struct rtnet_device *dev, void *addr, int alen, int newonly);
+void rt_dev_set_allmulti(struct rtnet_device *dev, int inc);
+
 #define rtnetdev_priv(dev) ((dev)->priv)
 
 #define rtdev_emerg(__dev, format, args...) \
diff --git a/kernel/drivers/net/stack/include/rtnet_socket.h b/kernel/drivers/net/stack/include/rtnet_socket.h
index b9cdf1968..dbf9b7c16 100644
--- a/kernel/drivers/net/stack/include/rtnet_socket.h
+++ b/kernel/drivers/net/stack/include/rtnet_socket.h
@@ -35,6 +35,8 @@
 #include <rtdm/driver.h>
 #include <stack_mgr.h>
 
+struct rtip_mc_socklist;
+
 struct rtsocket {
 	unsigned short protocol;
 
@@ -67,6 +69,8 @@ struct rtsocket {
 			int reg_index;	/* index in port registry */
 			u8 tos;
 			u8 state;
+			struct rtip_mc_socklist *mc_list;
+			u32 mc_if_addr;
 		} inet;
 
 		/* packet socket specific */
diff --git a/kernel/drivers/net/stack/include/rtskb.h b/kernel/drivers/net/stack/include/rtskb.h
index 84b69cffa..373dfedc5 100644
--- a/kernel/drivers/net/stack/include/rtskb.h
+++ b/kernel/drivers/net/stack/include/rtskb.h
@@ -172,6 +172,7 @@ struct rtskb {
 		struct icmphdr *icmph;
 		struct iphdr *ipihdr;
 		unsigned char *raw;
+		struct igmphdr *igmph;
 	} h;
 
 	/* network layer */
diff --git a/kernel/drivers/net/stack/ipv4/Kconfig b/kernel/drivers/net/stack/ipv4/Kconfig
index 8fb3c1acc..2c80a922c 100644
--- a/kernel/drivers/net/stack/ipv4/Kconfig
+++ b/kernel/drivers/net/stack/ipv4/Kconfig
@@ -62,6 +62,13 @@ config XENO_DRIVERS_NET_RTIPV4_ROUTER
 
     See Documentation/README.routing for further information.
 
+config XENO_DRIVERS_NET_RTIPV4_IGMP
+    bool "IGMP/multicast support"
+    depends on XENO_DRIVERS_NET_RTIPV4
+    default n
+    ---help---
+    Enables IGMP support of the RTnet Real-Time IPv4 protocol (multicast).
+
 config XENO_DRIVERS_NET_RTIPV4_DEBUG
     bool "RTipv4 Debugging"
     depends on XENO_DRIVERS_NET_RTIPV4
diff --git a/kernel/drivers/net/stack/ipv4/Makefile b/kernel/drivers/net/stack/ipv4/Makefile
index f0fcd36b8..decc4b10d 100644
--- a/kernel/drivers/net/stack/ipv4/Makefile
+++ b/kernel/drivers/net/stack/ipv4/Makefile
@@ -17,3 +17,4 @@ rtipv4-y := \
 	ip_fragment.o
 
 rtipv4-$(CONFIG_XENO_DRIVERS_NET_RTIPV4_ICMP) += icmp.o
+rtipv4-$(CONFIG_XENO_DRIVERS_NET_RTIPV4_IGMP) += igmp.o
diff --git a/kernel/drivers/net/stack/ipv4/af_inet.c b/kernel/drivers/net/stack/ipv4/af_inet.c
index 4cc66a355..9f79f0d20 100644
--- a/kernel/drivers/net/stack/ipv4/af_inet.c
+++ b/kernel/drivers/net/stack/ipv4/af_inet.c
@@ -34,6 +34,7 @@
 #include <ipv4/ip_output.h>
 #include <ipv4/protocol.h>
 #include <ipv4/route.h>
+#include <ipv4/igmp.h>
 
 MODULE_LICENSE("GPL");
 
@@ -288,6 +289,7 @@ static int __init rt_ipv4_proto_init(void)
 		rt_inet_protocols[i] = NULL;
 
 	rt_icmp_init();
+	rt_igmp_init();
 
 #ifdef CONFIG_XENO_OPT_VFILE
 	result = xnvfile_init_dir("ipv4", &ipv4_proc_root, &rtnet_proc_root);
@@ -313,6 +315,7 @@ err2:
 err1:
 #endif /* CONFIG_XENO_OPT_VFILE */
 
+	rt_igmp_release();
 	rt_icmp_release();
 	rt_arp_release();
 	rt_ip_release();
@@ -332,6 +335,8 @@ static void __exit rt_ipv4_proto_release(void)
 	xnvfile_destroy_dir(&ipv4_proc_root);
 #endif
 
+	rt_igmp_release();
+
 	/* Transport-Layer */
 	rt_icmp_release();
 
diff --git a/kernel/drivers/net/stack/ipv4/arp.c b/kernel/drivers/net/stack/ipv4/arp.c
index 2471879d9..46f9961a5 100644
--- a/kernel/drivers/net/stack/ipv4/arp.c
+++ b/kernel/drivers/net/stack/ipv4/arp.c
@@ -21,6 +21,8 @@
  *
  */
 
+#include <net/ip.h>
+#include <linux/if_arp.h>
 #include <rtdev.h>
 #include <stack_mgr.h>
 #include <ipv4/arp.h>
@@ -196,6 +198,30 @@ type:	__constant_htons(ETH_P_ARP),
 handler:&rt_arp_rcv
 };
 
+/* Multicast mapping */
+
+#ifdef CONFIG_XENO_DRIVERS_NET_RTIPV4_IGMP
+
+int rt_arp_mc_map(u32 addr, u8 *haddr, struct rtnet_device *dev, int dir)
+{
+    switch (dev->type) {
+    case ARPHRD_ETHER:
+    case ARPHRD_FDDI:
+    case ARPHRD_IEEE802:
+        ip_eth_mc_map(addr, haddr);
+        return 0;
+    default:
+        if (dir) {
+            memcpy(haddr, dev->broadcast, dev->addr_len);
+            return 0;
+        }
+    }
+    return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(rt_arp_mc_map);
+
+#endif
+
 /***
  *  rt_arp_init
  */
diff --git a/kernel/drivers/net/stack/ipv4/igmp.c b/kernel/drivers/net/stack/ipv4/igmp.c
new file mode 100644
index 000000000..3da21df5b
--- /dev/null
+++ b/kernel/drivers/net/stack/ipv4/igmp.c
@@ -0,0 +1,616 @@
+/*
+ *      ipv4/igmp.c - Internet Group Management Protocol  [IGMP]
+ *
+ *      Adapted from net/ipv4/igmp.c to RTnet by:
+ *              Gilles Chanteperdrix <gilles.chanteperdrix@xenomai.org>
+ *	Original author:
+ *		Alan Cox <Alan.Cox@linux.org>
+ *
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License
+ *	as published by the Free Software Foundation; either version
+ *	2 of the License, or (at your option) any later version.
+ *
+ *	Fixes:
+ *
+ *		Alan Cox	:	Added lots of __inline__ to optimise
+ *					the memory usage of all the tiny little
+ *					functions.
+ *		Alan Cox	:	Dumped the header building experiment.
+ *		Alan Cox	:	Minor tweaks ready for multicast routing
+ *					and extended IGMP protocol.
+ *		Alan Cox	:	Removed a load of inline directives. Gcc 2.5.8
+ *					writes utterly bogus code otherwise (sigh)
+ *					fixed IGMP loopback to behave in the manner
+ *					desired by mrouted, fixed the fact it has been
+ *					broken since 1.3.6 and cleaned up a few minor
+ *					points.
+ *
+ *		Chih-Jen Chang	:	Tried to revise IGMP to Version 2
+ *		Tsu-Sheng Tsao		E-mail: chihjenc@scf.usc.edu and tsusheng@scf.usc.edu
+ *					The enhancements are mainly based on Steve Deering's
+ *					ipmulti-3.5 source code.
+ *		Chih-Jen Chang	:	Added the igmp_get_mrouter_info and
+ *		Tsu-Sheng Tsao		igmp_set_mrouter_info to keep track of
+ *					the mrouted version on that device.
+ *		Chih-Jen Chang	:	Added the max_resp_time parameter to
+ *		Tsu-Sheng Tsao		igmp_heard_query(). Using this parameter
+ *					to identify the multicast router version
+ *					and do what the IGMP version 2 specified.
+ *		Chih-Jen Chang	:	Added a timer to revert to IGMP V2 router
+ *		Tsu-Sheng Tsao		if the specified time expired.
+ *		Alan Cox	:	Stop IGMP from 0.0.0.0 being accepted.
+ *		Alan Cox	:	Use GFP_ATOMIC in the right places.
+ *		Christian Daudt :	igmp timer wasn't set for local group
+ *					memberships but was being deleted,
+ *					which caused a "del_timer() called
+ *					from %p with timer not initialized\n"
+ *					message (960131).
+ *		Christian Daudt :	removed del_timer from
+ *					igmp_timer_expire function (960205).
+ *             Christian Daudt :       igmp_heard_report now only calls
+ *                                     igmp_timer_expire if tm->running is
+ *                                     true (960216).
+ *		Malcolm Beattie :	ttl comparison wrong in igmp_rcv made
+ *					igmp_heard_query never trigger. Expiry
+ *					miscalculation fixed in igmp_heard_query
+ *					and random() made to return unsigned to
+ *					prevent negative expiry times.
+ *		Alexey Kuznetsov:	Wrong group leaving behaviour, backport
+ *					fix from pending 2.1.x patches.
+ *		Alan Cox:		Forget to enable FDDI support earlier.
+ *		Alexey Kuznetsov:	Fixed leaving groups on device down.
+ *		Alexey Kuznetsov:	Accordance to igmp-v2-06 draft.
+ */
+
+#include <ipv4/igmp.h>
+#include <net/checksum.h>
+#include <net/ip.h>
+#include <rtnet_socket.h>
+#include <rtdev.h>
+#include <ipv4/protocol.h>
+#include <ipv4/route.h>
+#include <ipv4/arp.h>
+
+#define IGMP_REPLY_POOL_SIZE  8
+#define IP_MAX_MEMBERSHIPS 20
+#define RT_IGMP_SKB_PRIO     RTSKB_PRIO_VALUE(QUEUE_MIN_PRIO-1,		\
+						RTSKB_DEF_NRT_CHANNEL)
+/***
+ *  It is not part of the socket pool. It may furthermore be used concurrently
+ *  by multiple tasks because all fields are static excect skb_pool, but that
+ *  is spin lock protected.
+ */
+static struct rtsocket igmp_socket;
+static struct rtip_mc_list *mc_list;
+static rtdm_lock_t  mc_list_lock;
+static rtdm_mutex_t mc_socklist_lock;
+rtdm_task_t rtnet_igmp_task;
+
+#define IGMP_SIZE (sizeof(struct igmphdr)+sizeof(struct iphdr)+4)
+
+static int rt_igmp_send_report(struct rtnet_device *rtdev, u32 group, int type)
+{
+	struct rtskb *skb;
+	struct iphdr *iph;
+	struct igmphdr *ih;
+	struct dest_route rt;
+	u32 dst;
+	int len;
+	int err;
+	char buf[MAX_ADDR_LEN];
+	/* According to IGMPv2 specs, LEAVE messages are
+	 * sent to all-routers group.
+	 */
+	dst = group;
+	if (type == IGMP_HOST_LEAVE_MESSAGE)
+		dst = IGMP_ALL_ROUTER;
+	if (rt_arp_mc_map(dst, buf, rtdev, 0) == 0) {
+		memcpy(rt.dev_addr, buf, sizeof(buf));
+		rt.rtdev = rtdev;
+		rt.ip = dst;
+	}
+
+	len = (rtdev->hard_header_len + 15) & ~15;
+	skb = alloc_rtskb(len + IGMP_SIZE + 15, &global_pool);
+	if (skb == NULL) {
+		printk("can't alloc rtskb \n");
+		return -ENOMEM;
+	}
+
+	skb->rtdev = rtdev;
+	skb->priority = RT_IGMP_SKB_PRIO;
+	rtskb_reserve(skb, len);
+	skb->nh.iph = iph = (struct iphdr *)rtskb_put(skb, sizeof(*iph) + 4);
+	iph->version = 4;
+	iph->ihl = (sizeof(struct iphdr) + 4) >> 2;
+	iph->tos = 0xc0;
+	iph->frag_off = htons(IP_DF);
+	iph->ttl = 1;
+	iph->daddr = rt.ip;
+	iph->saddr = rtdev->local_ip;
+	iph->protocol = IPPROTO_IGMP;
+	iph->tot_len = htons(IGMP_SIZE);
+	iph->id = htons(0);
+	((u8 *) & iph[1])[0] = IPOPT_RA;
+	((u8 *) & iph[1])[1] = 4;
+	((u8 *) & iph[1])[2] = 0;
+	((u8 *) & iph[1])[3] = 0;
+	ip_send_check(iph);
+	ih = (struct igmphdr *)rtskb_put(skb, sizeof(struct igmphdr));
+	ih->type = type;
+	ih->code = 0;
+	ih->csum = 0;
+	ih->group = group;
+	ih->csum = ip_compute_csum((void *)ih, sizeof(struct igmphdr));
+
+	if (rtdev->hard_header) {
+		err = rtdev->hard_header(skb, rtdev, ETH_P_IP, rt.dev_addr,
+					 rtdev->dev_addr, skb->len);
+		if (err < 0) {
+		    kfree_rtskb(skb);
+		    return err;
+		}
+	}
+
+	return rtdev_xmit(skb);
+}
+
+static void igmp_heard_query(struct rtnet_device *rtdev, u32 group)
+{
+    struct rtip_mc_list	*im;
+    unsigned long     flags;
+
+    rtdm_lock_get_irqsave(&mc_list_lock, flags);
+    for (im = mc_list; im != NULL; im = im->next)
+	if (im->multiaddr != IGMP_ALL_HOSTS
+	    && (!group || im->multiaddr == group))
+	    im->state = RTIP_MC_DELAYING_MEMBER;
+    rtdm_lock_put_irqrestore(&mc_list_lock, flags);
+}
+
+static void igmp_heard_report(struct rtnet_device *rtdev, u32 group)
+{
+    struct rtip_mc_list	*im;
+    unsigned long     flags;
+
+    rtdm_lock_get_irqsave(&mc_list_lock, flags);
+    for (im = mc_list; im != NULL; im = im->next)
+	if (im->multiaddr == group
+	    && im->state == RTIP_MC_DELAYING_MEMBER)
+	    im->state = RTIP_MC_IDLE_MEMBER;
+    rtdm_lock_put_irqrestore(&mc_list_lock, flags);
+}
+
+void rt_igmp_rcv(struct rtskb *skb)
+{
+	/* This basically follows the spec line by line -- see RFC1112 */
+	struct igmphdr *ih = skb->h.igmph;
+	struct rtnet_device *rtdev = skb->rtdev;
+	int len = skb->len;
+	if (len < sizeof(struct igmphdr) || ip_compute_csum((void *)ih, len))
+		goto cleanup;
+
+	switch (ih->type) {
+	case IGMP_HOST_MEMBERSHIP_QUERY:
+		igmp_heard_query(rtdev, ih->group);
+		break;
+	case IGMP_HOST_MEMBERSHIP_REPORT:
+	case IGMP_HOST_NEW_MEMBERSHIP_REPORT:
+		igmp_heard_report(rtdev, ih->group);
+		break;
+	case IGMP_PIM:
+	case IGMP_DVMRP:
+	case IGMP_TRACE:
+	case IGMP_HOST_LEAVE_MESSAGE:
+	case IGMP_MTRACE:
+	case IGMP_MTRACE_RESP:
+		break;
+	default:
+		rtdm_printk(KERN_DEBUG
+			    "New IGMP type=0x%x, why we do not know about it?\n",
+			    ih->type);
+	}
+
+cleanup:
+	kfree_rtskb(skb);
+}
+
+/*
+ *	Add a filter to a device
+ */
+static void rt_ip_mc_filter_add(struct rtnet_device *rtdev, u32 addr)
+{
+	char buf[MAX_ADDR_LEN];
+
+	/* Checking for IFF_MULTICAST here is WRONG-WRONG-WRONG.
+	   We will get multicast token leakage, when IFF_MULTICAST
+	   is changed. This check should be done in dev->set_multicast_list
+	   routine. Something sort of:
+	   if (dev->mc_list && dev->flags&IFF_MULTICAST) { do it; }
+	   --ANK
+	 */
+	if (rt_arp_mc_map(addr, buf, rtdev, 0) == 0)
+		rt_dev_mc_add(rtdev, buf, rtdev->addr_len, 0);
+}
+
+/*
+ *	Remove a filter from a device
+ */
+static void rt_ip_mc_filter_del(struct rtnet_device *rtdev, u32 addr)
+{
+	char buf[MAX_ADDR_LEN];
+	struct rtnet_device *dev = rtdev;
+
+	if (rt_arp_mc_map(addr, buf, dev, 0) == 0)
+		rt_dev_mc_delete(dev, buf, dev->addr_len, 0);
+}
+
+static void igmp_group_dropped(struct rtip_mc_list *im)
+{
+    unsigned long flags;
+    enum rtip_mc_state oldstate;
+
+    rtdm_lock_get_irqsave(&mc_list_lock, flags);
+    oldstate = im->state;
+    if (oldstate != RTIP_MC_NON_MEMBER)
+	im->state = RTIP_MC_NON_MEMBER;
+    rtdm_lock_put_irqrestore(&mc_list_lock, flags);
+
+    if (oldstate != RTIP_MC_NON_MEMBER)
+	rt_ip_mc_filter_del(im->interface, im->multiaddr);
+}
+
+static void igmp_group_added(struct rtip_mc_list *im)
+{
+    unsigned long flags;
+    enum rtip_mc_state oldstate;
+
+    rtdm_lock_get_irqsave(&mc_list_lock, flags);
+    oldstate = im->state;
+    if (oldstate == RTIP_MC_NON_MEMBER) {
+	if (im->multiaddr == IGMP_ALL_HOSTS)
+	    im->state = RTIP_MC_IDLE_MEMBER;
+	else
+	    im->state = RTIP_MC_DELAYING_MEMBER;
+    }
+    rtdm_lock_put_irqrestore(&mc_list_lock, flags);
+
+    if (oldstate != RTIP_MC_NON_MEMBER) {
+	return;
+    }
+
+    rt_ip_mc_filter_add(im->interface, im->multiaddr);
+
+    if (im->multiaddr != IGMP_ALL_HOSTS && rtdm_in_rt_context())
+	rt_igmp_send_report(im->interface,
+			    im->multiaddr, IGMP_HOST_MEMBERSHIP_REPORT);
+}
+
+void rt_ip_mc_inc_group(struct rtnet_device *rtdev, u32 addr)
+{
+    struct rtip_mc_list *im, *iml;
+    unsigned long flags;
+
+    iml = rtdm_malloc(sizeof(*im));
+    if (!iml)
+	return;
+    iml->users = 1;
+    iml->interface = rtdev;
+    iml->multiaddr = addr;
+    iml->state = RTIP_MC_NON_MEMBER;
+
+    rtdm_lock_get_irqsave(&mc_list_lock, flags);
+    for (im = mc_list; im; im = im->next) {
+	if (im->multiaddr == addr && im->interface == rtdev) {
+	    im->users++;
+	    rtdm_lock_put_irqrestore(&mc_list_lock, flags);
+	    rtdm_free(iml);
+	    return;
+	}
+    }
+    iml->next = mc_list;
+    mc_list = iml;
+    rtdm_lock_put_irqrestore(&mc_list_lock, flags);
+
+    igmp_group_added(iml);
+}
+
+/*
+ *	A socket has left a multicast group on device dev
+ */
+void rt_ip_mc_dec_group(struct rtnet_device *rtdev, u32 addr)
+{
+    struct rtip_mc_list *i, **ip;
+    unsigned long	flags;
+    rtdm_lock_get_irqsave(&mc_list_lock, flags);
+    for (ip = &mc_list; (i = *ip) != NULL; ip = &i->next) {
+	if (i->multiaddr == addr && i->interface == rtdev) {
+	    if (--i->users == 0) {
+		*ip = i->next;
+		rtdm_lock_put_irqrestore(&mc_list_lock, flags);
+		igmp_group_dropped(i);
+		rtdm_free(i);
+		return;
+	    }
+	    break;
+	}
+    }
+    rtdm_lock_put_irqrestore(&mc_list_lock, flags);
+}
+
+static struct rtnet_device *rt_ip_mc_find_dev(struct ip_mreq *imr)
+{
+    struct rtnet_device *rtdev = NULL;
+
+    if (imr->imr_interface.s_addr)
+	rtdev = rt_ip_dev_find(imr->imr_interface.s_addr);
+
+    return rtdev;
+}
+
+/*
+ *	Join a socket to a group
+ */
+
+int rt_ip_mc_join_group(struct rtsocket *sk, struct ip_mreq *imr)
+{
+    int err = 0;
+    u32 addr = imr->imr_multiaddr.s_addr;
+    struct rtnet_device *rtdev = rt_ip_mc_find_dev(imr);
+    struct rtip_mc_socklist *i, *iml;
+
+    if (!rtdev)
+	return -ENODEV;
+
+    if (!IN_MULTICAST(ntohl(addr))) {
+	err = -EINVAL;
+	goto done;
+    }
+
+    iml = rtdm_malloc(sizeof(*iml));
+    if (!iml) {
+	err = -ENOMEM;
+	goto done;
+    }
+    iml->multi = *imr;
+
+    rtdm_mutex_lock(&mc_socklist_lock);
+    for (i = sk->prot.inet.mc_list; i; i = i->next)
+	    if (i->multi.imr_multiaddr.s_addr == addr &&
+		i->multi.imr_interface.s_addr == imr->imr_interface.s_addr) {
+		rtdm_mutex_unlock(&mc_socklist_lock);
+		rtdm_free(iml);
+		err = 0;
+		goto done;
+	    }
+
+    iml->next = sk->prot.inet.mc_list;
+    sk->prot.inet.mc_list = iml;
+    rtdm_mutex_unlock(&mc_socklist_lock);
+
+    rt_ip_mc_inc_group(rtdev, addr);
+
+  done:
+    rtdev_dereference(rtdev);
+    return err;
+}
+
+/*
+ *	Ask a socket to leave a group.
+ */
+int rt_ip_mc_leave_group(struct rtsocket *sk, struct ip_mreq *imr)
+{
+    u32 addr = imr->imr_multiaddr.s_addr;
+    struct  rtnet_device *rtdev = rt_ip_mc_find_dev(imr);
+    struct rtip_mc_socklist *i, **ip;
+
+    if (!rtdev)
+	return -ENODEV;
+
+    rtdm_mutex_lock(&mc_socklist_lock);
+    for (ip = &sk->prot.inet.mc_list; (i = *ip); ip = &i->next)
+	    if (i->multi.imr_multiaddr.s_addr == addr &&
+		i->multi.imr_interface.s_addr == imr->imr_interface.s_addr) {
+		*ip = i->next;
+		rtdm_mutex_unlock(&mc_socklist_lock);
+		goto found;
+	    }
+    rtdm_mutex_unlock(&mc_socklist_lock);
+
+    rtdev_dereference(rtdev);
+
+    return -EADDRNOTAVAIL;
+
+  found:
+    rt_igmp_send_report(rtdev, addr, IGMP_HOST_LEAVE_MESSAGE);
+    rt_ip_mc_dec_group(rtdev, addr);
+    rtdev_dereference(rtdev);
+
+    rtdm_free(i);
+
+    return 0;
+}
+
+/*
+ *	A socket is closing.
+ */
+void rt_ip_mc_drop_socket(struct rtsocket *sk)
+{
+    struct rtip_mc_socklist *i, *in;
+
+    if (sk->prot.inet.mc_list == NULL)
+	return;
+
+    for (i = sk->prot.inet.mc_list; i; i = in) {
+	struct rtnet_device *rtdev;
+
+	in = i->next;
+	rtdev = rt_ip_mc_find_dev(&i->multi);
+	if (!rtdev)
+	    continue;
+
+	rt_ip_mc_dec_group(rtdev, i->multi.imr_multiaddr.s_addr);
+	rtdev_dereference(rtdev);
+    }
+}
+
+static void process(void *arg)
+{
+    struct rtip_mc_list *im;
+    unsigned long flags;
+
+    while(!rtdm_task_should_stop()){
+	rtdm_lock_get_irqsave(&mc_list_lock, flags);
+	for (im = mc_list; im; im = im->next) {
+	    if (im->state == RTIP_MC_DELAYING_MEMBER) {
+		im->state = RTIP_MC_IDLE_MEMBER;
+		im->users++;
+		rtdev_reference(im->interface);
+		break;
+	    }
+	}
+	rtdm_lock_put_irqrestore(&mc_list_lock, flags);
+
+	if (im) {
+	    rt_igmp_send_report(im->interface,
+				im->multiaddr, IGMP_HOST_MEMBERSHIP_REPORT);
+	    rt_ip_mc_dec_group(im->interface, im->multiaddr);
+	    rtdev_dereference(im->interface);
+	}
+
+	rtdm_task_wait_period(NULL);
+    }
+}
+
+static int rt_igmp_socket(struct rtdm_fd *fd)
+{
+	/* we don't support user-created ICMP sockets */
+	return -ENOPROTOOPT;
+}
+
+static struct rtsocket *rt_igmp_dest_socket(struct rtskb *skb)
+{
+	/* Note that the socket's refcount is not used by this protocol.
+	 * The socket returned here is static and not part of the global pool. */
+	return &igmp_socket;
+}
+
+void rt_igmp_rcv_err(struct rtskb *skb)
+{
+	rtdm_printk("RTnet: rt_igmp_rcv err\n");
+}
+
+static struct rtinet_protocol igmp_protocol = {
+	.protocol = IPPROTO_IGMP,
+	.dest_socket = rt_igmp_dest_socket,
+	.rcv_handler = rt_igmp_rcv,
+	.err_handler = rt_igmp_rcv_err,
+	.init_socket = rt_igmp_socket
+};
+
+static void rt_ip_mc_unregister(struct rtnet_device *rtdev)
+{
+    struct rtip_mc_list *i, **ip;
+    unsigned long flags;
+
+    if (rtdev->flags & IFF_LOOPBACK)
+	return;
+
+  restart:
+    rtdm_lock_get_irqsave(&mc_list_lock, flags);
+    for (ip = &mc_list; (i = *ip) != NULL; ip = &i->next) {
+	if (i->interface != rtdev)
+	    continue;
+	*ip = i->next;
+	rtdm_lock_put_irqrestore(&mc_list_lock, flags);
+
+	igmp_group_dropped(i);
+	rtdm_free(i);
+	goto restart;
+    }
+    rtdm_lock_put_irqrestore(&mc_list_lock, flags);
+}
+
+static void rt_ip_mc_down(struct rtnet_device *rtdev)
+{
+    struct rtip_mc_list *i;
+    unsigned long flags;
+
+    if (rtdev->flags & IFF_LOOPBACK)
+	return;
+
+restart:
+    rtdm_lock_get_irqsave(&mc_list_lock, flags);
+    for (i = mc_list; i; i = i->next) {
+	if (i->interface != rtdev || i->state == RTIP_MC_NON_MEMBER)
+	    continue;
+	rtdm_lock_put_irqrestore(&mc_list_lock, flags);
+
+	igmp_group_dropped(i);
+	goto restart;
+    }
+    rtdm_lock_put_irqrestore(&mc_list_lock, flags);
+
+    rt_ip_mc_dec_group(rtdev, IGMP_ALL_HOSTS);
+}
+
+static void rt_ip_mc_up(struct rtnet_device *rtdev,
+			struct rtnet_core_cmd *up_cmd)
+{
+    struct rtip_mc_list *i;
+    unsigned long flags;
+
+    if (rtdev->flags & IFF_LOOPBACK)
+	return;
+
+    rt_ip_mc_inc_group(rtdev, IGMP_ALL_HOSTS);
+
+restart:
+    rtdm_lock_get_irqsave(&mc_list_lock, flags);
+    for (i = mc_list; i; i = i->next) {
+	if (i->interface != rtdev || i->state != RTIP_MC_NON_MEMBER)
+	    continue;
+	rtdm_lock_put_irqrestore(&mc_list_lock, flags);
+
+	igmp_group_added(i);
+	goto restart;
+    }
+    rtdm_lock_put_irqrestore(&mc_list_lock, flags);
+}
+
+static struct rtdev_event_hook rtdev_hook = {
+	.unregister_device = rt_ip_mc_unregister,
+	.ifup = rt_ip_mc_up,
+	.ifdown = rt_ip_mc_down,
+};
+
+void __init rt_igmp_init(void)
+{
+	unsigned int skbs;
+
+	igmp_socket.protocol = IPPROTO_IGMP;
+	igmp_socket.prot.inet.tos = 0;
+	igmp_socket.priority = 0;
+	rtdm_lock_init(&mc_list_lock);
+	rtdm_mutex_init(&mc_socklist_lock);
+	/* create the rtskb pool */
+	skbs = rtskb_pool_init(&igmp_socket.skb_pool, IGMP_REPLY_POOL_SIZE,
+			NULL, NULL);
+	if (skbs < IGMP_REPLY_POOL_SIZE)
+		printk("RTnet: allocated only %d igmp rtskbs\n", skbs);
+
+	rt_inet_add_protocol(&igmp_protocol);
+	rtdm_task_init(&rtnet_igmp_task, "igmp", process, 0,
+		       RTDM_TASK_LOWEST_PRIORITY, 10000000);
+	rtdev_add_event_hook(&rtdev_hook);
+}
+
+void rt_igmp_release(void)
+{
+	rtdev_del_event_hook(&rtdev_hook);
+	rtdm_task_destroy(&rtnet_igmp_task);
+	rt_inet_del_protocol(&igmp_protocol);
+	rtskb_pool_release(&igmp_socket.skb_pool);
+	rtdm_mutex_destroy(&mc_socklist_lock);
+}
diff --git a/kernel/drivers/net/stack/ipv4/ip_output.c b/kernel/drivers/net/stack/ipv4/ip_output.c
index 9cdfe3ec3..94db2f826 100644
--- a/kernel/drivers/net/stack/ipv4/ip_output.c
+++ b/kernel/drivers/net/stack/ipv4/ip_output.c
@@ -30,10 +30,19 @@
 #include <ipv4/ip_fragment.h>
 #include <ipv4/ip_input.h>
 #include <ipv4/route.h>
+#include <ipv4/igmp.h>
 
 static DEFINE_RTDM_LOCK(rt_ip_id_lock);
 static u16 rt_ip_id_count = 0;
 
+static inline u8 get_ttl(struct dest_route *rt)
+{
+	if (rtnet_in_multicast(ntohl(rt->ip)))
+		return 1;
+
+	return 255;
+}
+
 /***
  *  Slow path for fragmented packets
  */
@@ -107,7 +116,7 @@ int rt_ip_build_xmit_slow(struct rtsocket *sk,
 		iph->tot_len = htons(fraglen);
 		iph->id = htons(msg_rt_ip_id);
 		iph->frag_off = htons(frag_off);
-		iph->ttl = 255;
+		iph->ttl = get_ttl(rt);
 		iph->protocol = sk->protocol;
 		iph->saddr = rtdev->local_ip;
 		iph->daddr = rt->ip;
@@ -211,7 +220,7 @@ int rt_ip_build_xmit(struct rtsocket *sk,
 	iph->tot_len = htons(length);
 	iph->id = htons(msg_rt_ip_id);
 	iph->frag_off = htons(IP_DF);
-	iph->ttl = 255;
+	iph->ttl = get_ttl(rt);
 	iph->protocol = sk->protocol;
 	iph->saddr = rtdev->local_ip;
 	iph->daddr = rt->ip;
diff --git a/kernel/drivers/net/stack/ipv4/ip_sock.c b/kernel/drivers/net/stack/ipv4/ip_sock.c
index 9aff23f5e..96944a891 100644
--- a/kernel/drivers/net/stack/ipv4/ip_sock.c
+++ b/kernel/drivers/net/stack/ipv4/ip_sock.c
@@ -26,23 +26,68 @@
 #include <linux/in.h>
 
 #include <rtnet_socket.h>
+#include <ipv4/igmp.h>
 
 int rt_ip_setsockopt(struct rtsocket *s, int level, int optname,
 		     const void *optval, socklen_t optlen)
 {
-	int err = 0;
+	int err = 0, in_rt;
 
 	if (level != SOL_IP)
 		return -ENOPROTOOPT;
 
-	if (optlen < sizeof(unsigned int))
-		return -EINVAL;
+	in_rt = rtdm_in_rt_context();
 
 	switch (optname) {
 	case IP_TOS:
+		if (optlen < sizeof(unsigned int))
+			return -EINVAL;
+
 		s->prot.inet.tos = *(unsigned int *)optval;
 		break;
 
+#ifdef CONFIG_XENO_DRIVERS_NET_RTIPV4_IGMP
+	case IP_ADD_MEMBERSHIP: {
+		struct ip_mreq *mreq = (struct ip_mreq *)optval;
+
+		if (optlen < sizeof(*mreq))
+			return -EINVAL;
+
+		if (!in_rt)
+			return -ENOSYS;
+
+		err = rt_ip_mc_join_group(s, mreq);
+		break;
+	}
+
+	case IP_DROP_MEMBERSHIP: {
+		struct ip_mreq *mreq = (struct ip_mreq *)optval;
+
+		if (optlen < sizeof(*mreq))
+			return -EINVAL;
+
+		if (!in_rt)
+			return -ENOSYS;
+
+		err = rt_ip_mc_leave_group(s, mreq);
+		break;
+	}
+
+	case IP_MULTICAST_IF: {
+	    struct ip_mreq mreq;
+
+	    if (optlen < sizeof(struct in_addr))
+		return -EINVAL;
+
+	    if (optlen >= sizeof(mreq))
+		memcpy(&mreq, optval, sizeof(mreq));
+	    else
+		memcpy(&mreq.imr_interface, optval, sizeof(mreq.imr_interface));
+
+	    s->prot.inet.mc_if_addr = mreq.imr_interface.s_addr;
+	    break;
+	}
+#endif
 	default:
 		err = -ENOPROTOOPT;
 		break;
diff --git a/kernel/drivers/net/stack/ipv4/protocol.c b/kernel/drivers/net/stack/ipv4/protocol.c
index fee770eea..7a3efd145 100644
--- a/kernel/drivers/net/stack/ipv4/protocol.c
+++ b/kernel/drivers/net/stack/ipv4/protocol.c
@@ -28,6 +28,7 @@
 
 #include <rtnet_socket.h>
 #include <ipv4/protocol.h>
+#include <ipv4/igmp.h>
 
 struct rtinet_protocol *rt_inet_protocols[MAX_RT_INET_PROTOCOLS];
 
@@ -64,6 +65,7 @@ EXPORT_SYMBOL_GPL(rt_inet_del_protocol);
  */
 int rt_inet_socket(struct rtdm_fd *fd, int protocol)
 {
+        struct rtsocket *sock = rtdm_fd_to_private(fd);
 	struct rtinet_protocol *prot;
 
 	if (protocol == 0)
@@ -76,6 +78,8 @@ int rt_inet_socket(struct rtdm_fd *fd, int protocol)
 			break;
 		}
 
+	sock->prot.inet.mc_list = NULL;
+	sock->prot.inet.mc_if_addr = INADDR_ANY;
 	prot = rt_inet_protocols[rt_inet_hashkey(protocol)];
 
 	/* create the socket (call the socket creator) */
@@ -89,3 +93,16 @@ int rt_inet_socket(struct rtdm_fd *fd, int protocol)
 }
 
 EXPORT_SYMBOL_GPL(rt_inet_socket);
+
+int rt_inet_socket_cleanup(struct rtdm_fd *fd)
+{
+#ifdef CONFIG_XENO_DRIVERS_NET_RTIPV4_IGMP
+    struct rtsocket *sock = rtdm_fd_to_private(fd);
+    rt_ip_mc_drop_socket(sock);
+#endif
+
+    rt_socket_cleanup(fd);
+
+    return 0;
+}
+EXPORT_SYMBOL(rt_inet_socket_cleanup);
diff --git a/kernel/drivers/net/stack/ipv4/tcp/tcp.c b/kernel/drivers/net/stack/ipv4/tcp/tcp.c
index dc34683b0..a6d768cb0 100644
--- a/kernel/drivers/net/stack/ipv4/tcp/tcp.c
+++ b/kernel/drivers/net/stack/ipv4/tcp/tcp.c
@@ -1416,7 +1416,7 @@ static void rt_tcp_close(struct rtdm_fd *fd)
 
 	rt_tcp_socket_destruct(ts);
 
-	rt_socket_cleanup(fd);
+	rt_inet_socket_cleanup(fd);
 }
 
 /***
diff --git a/kernel/drivers/net/stack/ipv4/udp/udp.c b/kernel/drivers/net/stack/ipv4/udp/udp.c
index 0bae054b0..d4003d2ee 100644
--- a/kernel/drivers/net/stack/ipv4/udp/udp.c
+++ b/kernel/drivers/net/stack/ipv4/udp/udp.c
@@ -43,6 +43,8 @@
 #include <ipv4/protocol.h>
 #include <ipv4/route.h>
 #include <ipv4/udp.h>
+#include <ipv4/arp.h>
+#include <ipv4/igmp.h>
 
 /***
  *  This structure is used to register a UDP socket for reception. All
@@ -351,7 +353,7 @@ void rt_udp_close(struct rtdm_fd *fd)
 	while ((del = rtskb_dequeue(&sock->incoming)) != NULL)
 		kfree_rtskb(del);
 
-	rt_socket_cleanup(fd);
+	rt_inet_socket_cleanup(fd);
 }
 
 int rt_udp_ioctl(struct rtdm_fd *fd, unsigned int request, void __user * arg)
@@ -577,6 +579,36 @@ static int rt_udp_getfrag(const void *p, unsigned char *to,
 	return 0;
 }
 
+static int route_multicast(struct dest_route *rt,
+			   struct rtsocket *sock,
+			   u32 daddr, u32 *saddr)
+{
+	char buf[MAX_ADDR_LEN];
+
+	if (!rtnet_in_multicast(ntohl(daddr)))
+		return -ENOTSUPP;
+
+	if (sock->prot.inet.mc_if_addr != INADDR_ANY)
+	    *saddr = sock->prot.inet.mc_if_addr;
+	else if (*saddr == INADDR_ANY)
+		return -EHOSTUNREACH;
+
+	rt->rtdev = rt_ip_dev_find(*saddr);
+	if (rt->rtdev == NULL)
+		return -EHOSTUNREACH;
+
+	if (rt_arp_mc_map(daddr, buf, rt->rtdev, 0)) {
+		rtdev_dereference(rt->rtdev);
+		rtdm_printk("can't map multicast adress %08x \n", daddr);
+		return -EHOSTUNREACH;
+	}
+
+	memcpy(rt->dev_addr, buf, sizeof(buf));
+	rt->ip = daddr;
+
+	return 0;
+}
+
 /***
  *  rt_udp_sendmsg
  */
@@ -666,7 +698,9 @@ ssize_t rt_udp_sendmsg(struct rtdm_fd * fd, const struct user_msghdr * msg,
 	}
 
 	/* get output route */
-	err = rt_ip_route_output(&rt, daddr, saddr);
+	err = route_multicast(&rt, sock, daddr, &saddr);
+	if (err == -ENOTSUPP)
+		err = rt_ip_route_output(&rt, daddr, saddr);
 	if (err)
 		goto out;
 
@@ -684,7 +718,8 @@ ssize_t rt_udp_sendmsg(struct rtdm_fd * fd, const struct user_msghdr * msg,
 	err =
 	    rt_ip_build_xmit(sock, rt_udp_getfrag, &ufh, ulen, &rt, msg_flags);
 
-	/* Drop the reference obtained in rt_ip_route_output() */
+	/* Drop the reference obtained in either rt_ip_route_output()
+	   or route_multicast() */
 	rtdev_dereference(rt.rtdev);
 out:
 	rtdm_drop_iovec(iov, iov_fast);
@@ -729,7 +764,7 @@ struct rtsocket *rt_udp_dest_socket(struct rtskb *skb)
 		    csum_tcpudp_nofold(saddr, daddr, ulen, IPPROTO_UDP, 0);
 
 	/* patch broadcast daddr */
-	if (daddr == rtdev->broadcast_ip)
+	if (daddr == rtdev->broadcast_ip || rtnet_in_multicast(ntohl(daddr)))
 		daddr = rtdev->local_ip;
 
 	/* find the destination socket */
diff --git a/kernel/drivers/net/stack/rtdev.c b/kernel/drivers/net/stack/rtdev.c
index 91c464fe1..e577d8147 100644
--- a/kernel/drivers/net/stack/rtdev.c
+++ b/kernel/drivers/net/stack/rtdev.c
@@ -923,6 +923,208 @@ int rtdev_xmit_proxy(struct rtskb *rtskb)
 }
 #endif /* CONFIG_XENO_DRIVERS_NET_ADDON_PROXY */
 
+#ifdef CONFIG_XENO_DRIVERS_NET_RTIPV4_IGMP
+
+/* Find rtnet device by its local_ip adress */
+static inline struct rtnet_device * __rt_ip_dev_find(u32 addr){
+    int i;
+    struct rtnet_device *rtdev;
+
+    for (i = 0; i < MAX_RT_DEVICES; i++) {
+        rtdev = rtnet_devices[i];
+        if ((rtdev != NULL) && (rtdev->local_ip == addr)) {
+            return rtdev;
+        }
+    }
+    return NULL;
+}
+
+/***
+ *  rtdev_get_by_hwaddr - find and lock a rtnetdevice by its local ip adress
+ *  @addr:         Local  IP Adress
+  */
+struct rtnet_device *rt_ip_dev_find(u32 addr)
+{
+    struct rtnet_device * rtdev;
+    unsigned long flags;
+
+
+    rtdm_lock_get_irqsave(&rtnet_devices_rt_lock, flags);
+    rtdev = __rt_ip_dev_find(addr);
+    if (rtdev != NULL)
+        atomic_inc(&rtdev->refcount);
+    rtdm_lock_put_irqrestore(&rtnet_devices_rt_lock, flags);
+
+    return rtdev;
+}
+EXPORT_SYMBOL(rt_ip_dev_find);
+
+/*
+ *  Update the multicast list into the physical NIC controller.
+ */
+static void __rt_dev_mc_upload(struct rtnet_device *dev)
+{
+    /* Don't do anything till we up the interface
+     * [dev_open will call this function so the list will
+     * stay sane]
+     */
+
+    if (!(dev->flags&IFF_UP))
+        return;
+
+    /*
+     *  Devices with no set multicast or which have been
+     *  detached don't get set.
+     */
+
+    if (dev->set_multicast_list == NULL){
+        printk(KERN_INFO "RTnet: %s does not support multicast\n",
+	       dev->name);
+        return;
+    }
+    dev->set_multicast_list(dev);
+}
+
+void rt_dev_mc_upload(struct rtnet_device *dev)
+{
+    unsigned long flags;
+    rtdm_lock_get_irqsave(&dev->rtdev_lock, flags);
+    __rt_dev_mc_upload(dev);
+    rtdm_lock_put_irqrestore(&dev->rtdev_lock, flags);
+}
+
+/*
+ *  Delete a device level multicast
+ */
+
+int rt_dev_mc_delete(struct rtnet_device *dev, void *addr, int alen, int glbl)
+{
+    int err = 0;
+    struct rtdev_mc_list *dmi, **dmip;
+    unsigned long flags;
+
+    rtdm_lock_get_irqsave(&dev->rtdev_lock, flags);
+
+    for (dmip = &dev->mc_list; (dmi = *dmip) != NULL; dmip = &dmi->next) {
+        /*
+         *  Find the entry we want to delete. The device could
+         *  have variable length entries so check these too.
+         */
+        if (memcmp(dmi->dmi_addr, addr, dmi->dmi_addrlen) == 0 &&
+            alen == dmi->dmi_addrlen) {
+            if (glbl) {
+                int old_glbl = dmi->dmi_gusers;
+                dmi->dmi_gusers = 0;
+                if (old_glbl == 0)
+                    break;
+            }
+            if (--dmi->dmi_users)
+                goto done;
+
+            /*
+             *  Last user. So delete the entry.
+             */
+            *dmip = dmi->next;
+            dev->mc_count--;
+
+            /*
+             *  We have altered the list, so the card
+             *  loaded filter is now wrong. Fix it
+             */
+            __rt_dev_mc_upload(dev);
+
+            rtdm_lock_put_irqrestore(&dev->rtdev_lock, flags);
+
+            rtdm_free(dmi);
+            return 0;
+        }
+    }
+    err = -ENOENT;
+done:
+    rtdm_lock_put_irqrestore(&dev->rtdev_lock, flags);
+    return err;
+}
+EXPORT_SYMBOL(rt_dev_mc_delete);
+
+/*
+ *  Add a device level multicast
+ */
+
+
+int rt_dev_mc_add(struct rtnet_device *dev, void *addr, int alen, int glbl)
+{
+    int err = 0;
+    struct rtdev_mc_list *dmi, *dmi1;
+    unsigned long flags;
+
+    dmi1 = rtdm_malloc(sizeof(*dmi1));
+
+    rtdm_lock_get_irqsave(&dev->rtdev_lock, flags);
+    for (dmi = dev->mc_list; dmi != NULL; dmi = dmi->next) {
+        if (memcmp(dmi->dmi_addr, addr, dmi->dmi_addrlen) == 0 &&
+            dmi->dmi_addrlen == alen) {
+            if (glbl) {
+                int old_glbl = dmi->dmi_gusers;
+                dmi->dmi_gusers = 1;
+                if (old_glbl)
+                    goto done;
+            }
+            dmi->dmi_users++;
+            goto done;
+        }
+    }
+
+    if ((dmi = dmi1) == NULL) {
+        rtdm_lock_put_irqrestore(&dev->rtdev_lock, flags);
+        return -ENOMEM;
+    }
+    memcpy(dmi->dmi_addr, addr, alen);
+    dmi->dmi_addrlen = alen;
+    dmi->next = dev->mc_list;
+    dmi->dmi_users = 1;
+    dmi->dmi_gusers = glbl ? 1 : 0;
+    dev->mc_list = dmi;
+    dev->mc_count++;
+
+    __rt_dev_mc_upload(dev);
+
+    rtdm_lock_put_irqrestore(&dev->rtdev_lock, flags);
+    return 0;
+
+done:
+    rtdm_lock_put_irqrestore(&dev->rtdev_lock, flags);
+    if (dmi1)
+        rtdm_free(dmi1);
+    return err;
+}
+EXPORT_SYMBOL(rt_dev_mc_add);
+
+/*
+ *  Discard multicast list when a device is downed
+ */
+
+void rt_dev_mc_discard(struct rtnet_device *dev)
+{
+    unsigned long flags;
+
+    rtdm_lock_get_irqsave(&dev->rtdev_lock, flags);
+
+    while (dev->mc_list != NULL) {
+        struct rtdev_mc_list *tmp = dev->mc_list;
+        dev->mc_list = tmp->next;
+        if (tmp->dmi_users > tmp->dmi_gusers)
+            printk("dev_mc_discard: multicast leakage! dmi_users=%d\n", tmp->dmi_users);
+        rtdm_lock_put_irqrestore(&dev->rtdev_lock, flags);
+        rtdm_free(tmp);
+        rtdm_lock_get_irqsave(&dev->rtdev_lock, flags);
+    }
+    dev->mc_count = 0;
+
+    rtdm_lock_put_irqrestore(&dev->rtdev_lock, flags);
+}
+
+#endif	/* CONFIG_XENO_DRIVERS_NET_RTIPV4_IGMP */
+
 unsigned int rt_hard_mtu(struct rtnet_device *rtdev, unsigned int priority)
 {
 	return rtdev->mtu;
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH 03/16] utils/net: rtifconfig: display device name untruncated
  2019-03-21 17:13 [PATCH 00/16] multicast, VLAN support for RTnet Philippe Gerum
  2019-03-21 17:13 ` [PATCH 01/16] net/stack: plan for merging private device flags with netdev_priv_flags Philippe Gerum
  2019-03-21 17:13 ` [PATCH 02/16] net/stack: add multicast support Philippe Gerum
@ 2019-03-21 17:13 ` Philippe Gerum
  2019-03-21 17:13 ` [PATCH 04/16] net/stack: add support for VLAN filtering Philippe Gerum
                   ` (12 subsequent siblings)
  15 siblings, 0 replies; 19+ messages in thread
From: Philippe Gerum @ 2019-03-21 17:13 UTC (permalink / raw)
  To: xenomai; +Cc: Gilles Chanteperdrix, Philippe Gerum

From: Gilles Chanteperdrix <gilles.chanteperdrix@xenomai.org>

Signed-off-by: Philippe Gerum <rpm@xenomai.org>
---
 utils/net/rtifconfig.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/utils/net/rtifconfig.c b/utils/net/rtifconfig.c
index 8117e127c..9a9abfc4c 100644
--- a/utils/net/rtifconfig.c
+++ b/utils/net/rtifconfig.c
@@ -183,7 +183,7 @@ void print_dev(void)
     struct itf_stats *itf;
 
 
-    cmd.head.if_name[9] = 0;
+    cmd.head.if_name[IFNAMSIZ - 1] = 0;
 
     printf("%-9s Medium: ", cmd.head.if_name);
 
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH 04/16] net/stack: add support for VLAN filtering
  2019-03-21 17:13 [PATCH 00/16] multicast, VLAN support for RTnet Philippe Gerum
                   ` (2 preceding siblings ...)
  2019-03-21 17:13 ` [PATCH 03/16] utils/net: rtifconfig: display device name untruncated Philippe Gerum
@ 2019-03-21 17:13 ` Philippe Gerum
  2019-03-21 17:13 ` [PATCH 05/16] utils/net: add VLAN filter configuration tool Philippe Gerum
                   ` (11 subsequent siblings)
  15 siblings, 0 replies; 19+ messages in thread
From: Philippe Gerum @ 2019-03-21 17:13 UTC (permalink / raw)
  To: xenomai; +Cc: Gilles Chanteperdrix, Philippe Gerum

From: Gilles Chanteperdrix <gilles.chanteperdrix@xenomai.org>

Signed-off-by: Philippe Gerum <rpm@xenomai.org>
---
 kernel/drivers/net/addons/cap.c               |  47 +-
 kernel/drivers/net/stack/Kconfig              |   7 +
 kernel/drivers/net/stack/Makefile             |   2 +
 kernel/drivers/net/stack/include/rtdev.h      |  19 +
 kernel/drivers/net/stack/include/rtif_vlan.h  | 105 +++
 kernel/drivers/net/stack/include/rtnet_port.h |   6 +-
 kernel/drivers/net/stack/include/rtskb.h      |   1 +
 kernel/drivers/net/stack/include/rtvlan.h     |  25 +
 kernel/drivers/net/stack/rtdev.c              |  32 +-
 kernel/drivers/net/stack/rtnet_chrdev.c       |   7 +-
 kernel/drivers/net/stack/rtnet_module.c       |   5 +
 kernel/drivers/net/stack/socket.c             |  16 +-
 kernel/drivers/net/stack/vlan.c               | 725 ++++++++++++++++++
 13 files changed, 967 insertions(+), 30 deletions(-)
 create mode 100644 kernel/drivers/net/stack/include/rtif_vlan.h
 create mode 100644 kernel/drivers/net/stack/include/rtvlan.h
 create mode 100644 kernel/drivers/net/stack/vlan.c

diff --git a/kernel/drivers/net/addons/cap.c b/kernel/drivers/net/addons/cap.c
index b901bedcf..e28f3dd0c 100644
--- a/kernel/drivers/net/addons/cap.c
+++ b/kernel/drivers/net/addons/cap.c
@@ -57,6 +57,25 @@ static struct tap_device_t {
 
 void rtcap_rx_hook(struct rtskb *rtskb)
 {
+	int                     ifindex;
+	int                     active;
+
+	if (rtskb->cap_flags & RTSKB_CAP_SHARED)
+		return;
+
+	ifindex = rtskb->rtdev->ifindex;
+	active  = tap_device[ifindex].present & (TAP_DEV | RTMAC_TAP_DEV);
+
+	if ((active & TAP_DEV)
+		&& !(tap_device[ifindex].tap_dev->flags & IFF_UP))
+		active &= ~TAP_DEV;
+	if ((active & RTMAC_TAP_DEV)
+		&& !(tap_device[ifindex].rtmac_tap_dev->flags & IFF_UP))
+		active &= ~RTMAC_TAP_DEV;
+
+	if (active == 0)
+		return;
+
 	if ((rtskb->cap_comp_skb = rtskb_pool_dequeue(&cap_pool)) == 0) {
 		tap_device[rtskb->rtdev->ifindex].tap_dev_stats.rx_dropped++;
 		return;
@@ -70,6 +89,7 @@ void rtcap_rx_hook(struct rtskb *rtskb)
 	rtskb->cap_next = NULL;
 
 	rtskb->cap_flags |= RTSKB_CAP_SHARED;
+	rtskb->cap_dev = rtskb->rtdev;
 
 	rtdm_nrtsig_pend(&cap_signal);
 }
@@ -78,16 +98,24 @@ int rtcap_xmit_hook(struct rtskb *rtskb, struct rtnet_device *rtdev)
 {
 	struct tap_device_t *tap_dev = &tap_device[rtskb->rtdev->ifindex];
 	rtdm_lockctx_t context;
+	int active;
 
-	if ((rtskb->cap_comp_skb = rtskb_pool_dequeue(&cap_pool)) == 0) {
+	active = tap_dev->present & XMIT_HOOK;
+	if (active && !(tap_dev->tap_dev->flags & IFF_UP))
+		active &= ~XMIT_HOOK;
+
+	if (!active
+		|| (rtskb->cap_flags & RTSKB_CAP_SHARED)
+		|| (rtskb->cap_comp_skb = rtskb_pool_dequeue(&cap_pool)) == 0) {
 		tap_dev->tap_dev_stats.rx_dropped++;
-		return tap_dev->orig_xmit(rtskb, rtdev);
+		goto done;
 	}
 
 	rtskb->cap_next = NULL;
 	rtskb->cap_start = rtskb->data;
 	rtskb->cap_len = rtskb->len;
 	rtskb->cap_flags |= RTSKB_CAP_SHARED;
+	rtskb->cap_dev = rtdev;
 
 	rtskb->time_stamp = rtdm_clock_read();
 
@@ -102,7 +130,7 @@ int rtcap_xmit_hook(struct rtskb *rtskb, struct rtnet_device *rtdev)
 	rtdm_lock_put_irqrestore(&rtcap_lock, context);
 
 	rtdm_nrtsig_pend(&cap_signal);
-
+done:
 	return tap_dev->orig_xmit(rtskb, rtdev);
 }
 
@@ -174,7 +202,7 @@ static void rtcap_signal_handler(rtdm_nrtsig_t * nrtsig, void *arg)
 
 		rtdm_lock_put_irqrestore(&rtcap_lock, context);
 
-		ifindex = rtskb->rtdev->ifindex;
+		ifindex = rtskb->cap_dev->ifindex;
 		active = tap_device[ifindex].present;
 
 		if (active) {
@@ -332,6 +360,7 @@ void cleanup_tap_devices(void)
 
 			unregister_netdev(tap_device[i].tap_dev);
 			free_netdev(tap_device[i].tap_dev);
+			tap_device[i].present = 0;
 		}
 }
 
@@ -474,19 +503,21 @@ void rtcap_cleanup(void)
 {
 	rtdm_lockctx_t context;
 
-	rtdm_nrtsig_destroy(&cap_signal);
-
 	/* unregister capturing handlers
 	 * (take lock to avoid any unloading code before handler was left) */
 	rtdm_lock_get_irqsave(&rtcap_lock, context);
 	rtcap_handler = NULL;
 	rtdm_lock_put_irqrestore(&rtcap_lock, context);
 
+	cleanup_tap_devices();
+
+	msleep(10);
+
+	rtdm_nrtsig_destroy(&cap_signal);
+
 	/* empty queue (should be already empty) */
 	rtcap_signal_handler(0, NULL /* we ignore them anyway */ );
 
-	cleanup_tap_devices();
-
 	rtskb_pool_release(&cap_pool);
 
 	printk("RTcap: unloaded\n");
diff --git a/kernel/drivers/net/stack/Kconfig b/kernel/drivers/net/stack/Kconfig
index 830cec5ad..47a6f290d 100644
--- a/kernel/drivers/net/stack/Kconfig
+++ b/kernel/drivers/net/stack/Kconfig
@@ -31,6 +31,13 @@ config XENO_DRIVERS_NET_RTWLAN
     on low-level access to 802.11-compliant adapters and is currently
     in an experimental stage.
 
+config XENO_DRIVERS_NET_VLAN
+    depends on XENO_DRIVERS_NET
+    bool "Real-Time VLAN"
+    select XENO_DRIVERS_NET_RTIPV4_IGMP
+    ---help---
+    Enables core support for real-time VLAN.
+
 comment "Protocols"
 
 source "drivers/xenomai/net/stack/ipv4/Kconfig"
diff --git a/kernel/drivers/net/stack/Makefile b/kernel/drivers/net/stack/Makefile
index d055dc2af..8873f7022 100644
--- a/kernel/drivers/net/stack/Makefile
+++ b/kernel/drivers/net/stack/Makefile
@@ -24,3 +24,5 @@ rtnet-y :=  \
 	eth.o
 
 rtnet-$(CONFIG_XENO_DRIVERS_NET_RTWLAN) += rtwlan.o
+
+rtnet-$(CONFIG_XENO_DRIVERS_NET_VLAN) += vlan.o
diff --git a/kernel/drivers/net/stack/include/rtdev.h b/kernel/drivers/net/stack/include/rtdev.h
index fe015c338..65c7ed3dc 100644
--- a/kernel/drivers/net/stack/include/rtdev.h
+++ b/kernel/drivers/net/stack/include/rtdev.h
@@ -153,6 +153,13 @@ struct rtnet_device {
 	int (*hard_start_xmit) (struct rtskb * skb, struct rtnet_device * dev);
 	int (*hw_reset) (struct rtnet_device * rtdev);
 	void (*set_multicast_list) (struct rtnet_device *rtdev);
+	void (*vlan_rx_add_vid)(struct rtnet_device *dev,
+				unsigned short vid);
+	void (*vlan_rx_kill_vid)(struct rtnet_device *dev,
+				unsigned short vid);
+#ifdef CONFIG_XENO_DRIVERS_NET_VLAN
+	struct list_head	vlan_link;
+#endif
 
 	/* Transmission hook, managed by the stack core, RTcap, and RTmac
 	 *
@@ -191,6 +198,18 @@ extern struct list_head event_hook_list;
 extern struct mutex rtnet_devices_nrt_lock;
 extern struct rtnet_device *rtnet_devices[];
 
+#ifdef CONFIG_XENO_DRIVERS_NET_VLAN
+extern struct rtnet_device *
+__rtdev_real_dev(struct rtnet_device *dev) __attribute__((pure));
+#else
+static inline struct rtnet_device *__rtdev_real_dev(struct rtnet_device *dev)
+{
+	return dev;
+}
+#endif
+#define rtdev_mc_list(dev) __rtdev_real_dev(dev)->mc_list
+#define rtdev_mc_count(dev) __rtdev_real_dev(dev)->mc_count
+
 int __rt_init_etherdev(struct rtnet_device *rtdev,
 		       unsigned int dev_pool_size, struct module *module);
 
diff --git a/kernel/drivers/net/stack/include/rtif_vlan.h b/kernel/drivers/net/stack/include/rtif_vlan.h
new file mode 100644
index 000000000..d1cc9fa4b
--- /dev/null
+++ b/kernel/drivers/net/stack/include/rtif_vlan.h
@@ -0,0 +1,105 @@
+/*
+ * VLAN		An implementation of 802.1Q VLAN tagging.
+ *
+ * Authors:	Ben Greear <greearb@candelatech.com>
+ *
+ *		This program is free software; you can redistribute it and/or
+ *		modify it under the terms of the GNU General Public License
+ *		as published by the Free Software Foundation; either version
+ *		2 of the License, or (at your option) any later version.
+ *
+ */
+#ifndef _RTNET_IF_VLAN_H_
+#define _RTNET_IF_VLAN_H_
+
+#include <rtdev.h>
+#include <rtskb.h>
+#include <uapi/linux/if_vlan.h>
+#include <linux/if_vlan.h>
+
+/* found in socket.c */
+extern void rtvlan_ioctl_set(int (*hook)(struct net *, void __user *));
+
+static inline bool is_rtvlan_dev(struct rtnet_device *dev)
+{
+	return !!(dev->priv_flags & IFF_802_1Q_VLAN);
+}
+
+struct rtvlan_pcpu_stats {
+	u64			rx_packets;
+	u64			rx_bytes;
+	u64			rx_multicast;
+	u64			tx_packets;
+	u64			tx_bytes;
+	seqcount_t		syncp;
+	u32			rx_errors;
+	u32			tx_dropped;
+};
+
+struct rtvlan_dev_priv {
+	unsigned int				nr_ingress_mappings;
+	u32					ingress_priority_map[8];
+	unsigned int				nr_egress_mappings;
+	struct vlan_priority_tci_mapping	*egress_priority_map[16];
+
+	__be16					vlan_proto;
+	u16					vlan_id;
+	u16					flags;
+
+	struct rtnet_device			*real_dev;
+	unsigned char				real_dev_addr[ETH_ALEN];
+
+	struct rtvlan_pcpu_stats __percpu	*vlan_pcpu_stats;
+	struct net_device_stats			stats;
+	unsigned int				nest_level;
+};
+
+static inline struct rtvlan_dev_priv *rtvlan_dev_priv(const struct rtnet_device *dev)
+{
+	return dev->priv;
+}
+
+static inline u16
+rtvlan_dev_get_egress_qos_mask(struct rtnet_device *dev, u32 skprio)
+{
+	struct vlan_priority_tci_mapping *mp;
+
+	smp_rmb(); /* coupled with smp_wmb() in rtvlan_dev_set_egress_priority() */
+
+	mp = rtvlan_dev_priv(dev)->egress_priority_map[(skprio & 0xF)];
+	while (mp) {
+		if (mp->priority == skprio) {
+			return mp->vlan_qos; /* This should already be shifted
+					      * to mask correctly with the
+					      * VLAN's TCI */
+		}
+		mp = mp->next;
+	}
+	return 0;
+}
+
+static inline void
+rtvlan_insert_tag(struct rtskb *skb, __be16 vlan_proto, u16 vlan_tci)
+{
+	struct vlan_ethhdr *veth;
+
+	veth = (struct vlan_ethhdr *)rtskb_push(skb, VLAN_HLEN);
+
+	/* Move the mac addresses to the beginning of the new header. */
+	memmove(skb->data, skb->data + VLAN_HLEN, 2 * ETH_ALEN);
+
+	/* first, the ethernet type */
+	veth->h_vlan_proto = vlan_proto;
+
+	/* now, the TCI */
+	veth->h_vlan_TCI = htons(vlan_tci);
+}
+
+static inline void
+rtvlan_put_tag(struct rtskb *skb, __be16 vlan_proto, u16 vlan_tci)
+{
+	rtvlan_insert_tag(skb, vlan_proto, vlan_tci);
+	skb->protocol = vlan_proto;
+}
+
+#endif /* !(_RTNET_IF_VLAN_H_) */
diff --git a/kernel/drivers/net/stack/include/rtnet_port.h b/kernel/drivers/net/stack/include/rtnet_port.h
index 37f907027..9f7e835a7 100644
--- a/kernel/drivers/net/stack/include/rtnet_port.h
+++ b/kernel/drivers/net/stack/include/rtnet_port.h
@@ -58,12 +58,12 @@ static inline int rtnetif_queue_stopped(struct rtnet_device *rtdev)
 
 static inline int rtnetif_running(struct rtnet_device *rtdev)
 {
-	return test_bit(__RTNET_LINK_STATE_START, &rtdev->link_state);
+	return test_bit(__RTNET_LINK_STATE_START, &__rtdev_real_dev(rtdev)->link_state);
 }
 
 static inline int rtnetif_device_present(struct rtnet_device *rtdev)
 {
-	return test_bit(__RTNET_LINK_STATE_PRESENT, &rtdev->link_state);
+	return test_bit(__RTNET_LINK_STATE_PRESENT, &__rtdev_real_dev(rtdev)->link_state);
 }
 
 static inline void rtnetif_device_detach(struct rtnet_device *rtdev)
@@ -99,7 +99,7 @@ static inline void rtnetif_carrier_off(struct rtnet_device *rtdev)
 
 static inline int rtnetif_carrier_ok(struct rtnet_device *rtdev)
 {
-	return !test_bit(__RTNET_LINK_STATE_NOCARRIER, &rtdev->link_state);
+	return !test_bit(__RTNET_LINK_STATE_NOCARRIER, &__rtdev_real_dev(rtdev)->link_state);
 }
 
 #define NIPQUAD(addr) \
diff --git a/kernel/drivers/net/stack/include/rtskb.h b/kernel/drivers/net/stack/include/rtskb.h
index 373dfedc5..36445ad08 100644
--- a/kernel/drivers/net/stack/include/rtskb.h
+++ b/kernel/drivers/net/stack/include/rtskb.h
@@ -214,6 +214,7 @@ struct rtskb {
 	unsigned char *cap_start;	/* start offset for capturing           */
 	unsigned int cap_len;	/* capture length of this rtskb         */
 	nanosecs_abs_t cap_rtmac_stamp;	/* RTmac enqueuing time            */
+        struct rtnet_device *cap_dev;	 /* Captured interface */
 #endif
 
 	struct list_head entry;	/* for global rtskb list */
diff --git a/kernel/drivers/net/stack/include/rtvlan.h b/kernel/drivers/net/stack/include/rtvlan.h
new file mode 100644
index 000000000..a6fd3df91
--- /dev/null
+++ b/kernel/drivers/net/stack/include/rtvlan.h
@@ -0,0 +1,25 @@
+#ifndef RTNET_RTVLAN_H
+#define RTNET_RTVLAN_H
+
+#ifdef CONFIG_XENO_DRIVERS_NET_VLAN
+void rtvlan_proto_init(void);
+
+void rtvlan_proto_release(void);
+
+int rtvlan_ioctl_handler(void __user *arg);
+#else
+static inline void rtvlan_proto_init(void)
+{
+}
+
+static inline void rtvlan_proto_release(void)
+{
+}
+
+static inline int rtvlan_ioctl_handler(void __user *arg)
+{
+	return -ENOSYS;
+}
+#endif
+
+#endif /* RTNET_RTVLAN_H */
diff --git a/kernel/drivers/net/stack/rtdev.c b/kernel/drivers/net/stack/rtdev.c
index e577d8147..a1bca2456 100644
--- a/kernel/drivers/net/stack/rtdev.c
+++ b/kernel/drivers/net/stack/rtdev.c
@@ -329,6 +329,9 @@ static void init_etherdev(struct rtnet_device *rtdev, struct module *module)
 	rtdev->flags = IFF_BROADCAST;	/* TODO: IFF_MULTICAST; */
 	rtdev->get_mtu = rt_hard_mtu;
 	rtdev->rt_owner = module;
+#ifdef CONFIG_XENO_DRIVERS_NET_VLAN
+	INIT_LIST_HEAD(&rtdev->vlan_link);
+#endif
 
 	memset(rtdev->broadcast, 0xFF, ETH_ALEN);
 	strcpy(rtdev->name, "rteth%d");
@@ -528,6 +531,15 @@ int rt_register_rtnetdev(struct rtnet_device *rtdev)
 	if (rtdev->vers < RTDEV_VERS_2_0)
 		return -EINVAL;
 
+#ifdef CONFIG_XENO_DRIVERS_NET_VLAN
+	if ((rtdev->features & NETIF_F_HW_VLAN_CTAG_FILTER) &&
+	    (!rtdev->vlan_rx_add_vid || !rtdev->vlan_rx_kill_vid)) {
+	    printk("RTnet: %s has VLAN hardware filtering but does not provide "
+		    "callbacks\n", rtdev->name);
+	    return -EINVAL;
+	}
+#endif
+
 	if (rtdev->features & NETIF_F_LLTX)
 		rtdev->start_xmit = rtdev->hard_start_xmit;
 	else
@@ -1005,7 +1017,7 @@ int rt_dev_mc_delete(struct rtnet_device *dev, void *addr, int alen, int glbl)
 
     rtdm_lock_get_irqsave(&dev->rtdev_lock, flags);
 
-    for (dmip = &dev->mc_list; (dmi = *dmip) != NULL; dmip = &dmi->next) {
+    for (dmip = &rtdev_mc_list(dev); (dmi = *dmip) != NULL; dmip = &dmi->next) {
         /*
          *  Find the entry we want to delete. The device could
          *  have variable length entries so check these too.
@@ -1025,7 +1037,7 @@ int rt_dev_mc_delete(struct rtnet_device *dev, void *addr, int alen, int glbl)
              *  Last user. So delete the entry.
              */
             *dmip = dmi->next;
-            dev->mc_count--;
+            rtdev_mc_count(dev)--;
 
             /*
              *  We have altered the list, so the card
@@ -1060,7 +1072,7 @@ int rt_dev_mc_add(struct rtnet_device *dev, void *addr, int alen, int glbl)
     dmi1 = rtdm_malloc(sizeof(*dmi1));
 
     rtdm_lock_get_irqsave(&dev->rtdev_lock, flags);
-    for (dmi = dev->mc_list; dmi != NULL; dmi = dmi->next) {
+    for (dmi = rtdev_mc_list(dev); dmi != NULL; dmi = dmi->next) {
         if (memcmp(dmi->dmi_addr, addr, dmi->dmi_addrlen) == 0 &&
             dmi->dmi_addrlen == alen) {
             if (glbl) {
@@ -1080,11 +1092,11 @@ int rt_dev_mc_add(struct rtnet_device *dev, void *addr, int alen, int glbl)
     }
     memcpy(dmi->dmi_addr, addr, alen);
     dmi->dmi_addrlen = alen;
-    dmi->next = dev->mc_list;
+    dmi->next = rtdev_mc_list(dev);
     dmi->dmi_users = 1;
     dmi->dmi_gusers = glbl ? 1 : 0;
-    dev->mc_list = dmi;
-    dev->mc_count++;
+    rtdev_mc_list(dev) = dmi;
+    rtdev_mc_count(dev)++;
 
     __rt_dev_mc_upload(dev);
 
@@ -1109,16 +1121,16 @@ void rt_dev_mc_discard(struct rtnet_device *dev)
 
     rtdm_lock_get_irqsave(&dev->rtdev_lock, flags);
 
-    while (dev->mc_list != NULL) {
-        struct rtdev_mc_list *tmp = dev->mc_list;
-        dev->mc_list = tmp->next;
+    while (rtdev_mc_list(dev) != NULL) {
+        struct rtdev_mc_list *tmp = rtdev_mc_list(dev);
+        rtdev_mc_list(dev) = tmp->next;
         if (tmp->dmi_users > tmp->dmi_gusers)
             printk("dev_mc_discard: multicast leakage! dmi_users=%d\n", tmp->dmi_users);
         rtdm_lock_put_irqrestore(&dev->rtdev_lock, flags);
         rtdm_free(tmp);
         rtdm_lock_get_irqsave(&dev->rtdev_lock, flags);
     }
-    dev->mc_count = 0;
+    rtdev_mc_count(dev) = 0;
 
     rtdm_lock_put_irqrestore(&dev->rtdev_lock, flags);
 }
diff --git a/kernel/drivers/net/stack/rtnet_chrdev.c b/kernel/drivers/net/stack/rtnet_chrdev.c
index d9a37e5a2..88bceaab8 100644
--- a/kernel/drivers/net/stack/rtnet_chrdev.c
+++ b/kernel/drivers/net/stack/rtnet_chrdev.c
@@ -30,6 +30,7 @@
 #include <linux/netdevice.h>
 #include <linux/spinlock.h>
 
+#include <rtnet_port.h>
 #include <rtnet_chrdev.h>
 #include <rtnet_internal.h>
 #include <ipv4/route.h>
@@ -126,10 +127,8 @@ static int rtnet_core_ioctl(struct rtnet_device *rtdev, unsigned int request,
 		cmd.args.info.mtu = rtdev->mtu;
 		cmd.args.info.flags = rtdev->flags;
 		if ((cmd.args.info.flags & IFF_UP)
-		    && (rtdev->link_state
-			& (RTNET_LINK_STATE_PRESENT
-			   | RTNET_LINK_STATE_NOCARRIER))
-		    == RTNET_LINK_STATE_PRESENT)
+		    && rtnetif_carrier_ok(rtdev)
+		    && rtnetif_device_present(rtdev))
 			cmd.args.info.flags |= IFF_RUNNING;
 
 		memcpy(cmd.args.info.dev_addr, rtdev->dev_addr, MAX_ADDR_LEN);
diff --git a/kernel/drivers/net/stack/rtnet_module.c b/kernel/drivers/net/stack/rtnet_module.c
index ed6037146..c0b7ff7f1 100644
--- a/kernel/drivers/net/stack/rtnet_module.c
+++ b/kernel/drivers/net/stack/rtnet_module.c
@@ -34,6 +34,7 @@
 #include <rtnet_rtpc.h>
 #include <stack_mgr.h>
 #include <rtwlan.h>
+#include <rtvlan.h>
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("RTnet stack core");
@@ -353,6 +354,8 @@ int __init rtnet_init(void)
 	if ((err = rtpc_init()) != 0)
 		goto err_out6;
 
+	rtvlan_proto_init();
+
 	rtnet_corectl_register();
 
 	return 0;
@@ -388,6 +391,8 @@ void __exit rtnet_release(void)
 {
 	rtnet_corectl_unregister();
 
+	rtvlan_proto_release();
+
 	rtpc_cleanup();
 
 	rtwlan_exit();
diff --git a/kernel/drivers/net/stack/socket.c b/kernel/drivers/net/stack/socket.c
index 832c96f00..92e33ce46 100644
--- a/kernel/drivers/net/stack/socket.c
+++ b/kernel/drivers/net/stack/socket.c
@@ -36,6 +36,8 @@
 #include <rtnet_internal.h>
 #include <rtnet_iovec.h>
 #include <rtnet_socket.h>
+#include <rtvlan.h>
+#include <rtnet_port.h>
 #include <ipv4/protocol.h>
 
 #define SKB_POOL_CLOSED     0
@@ -246,7 +248,8 @@ int rt_socket_if_ioctl(struct rtdm_fd *fd, int request, void __user * arg)
 	int ret = 0, size = 0, i;
 	short flags;
 
-	if (request == SIOCGIFCONF) {
+	switch (request) {
+	case SIOCGIFCONF: {
 		u_ifc = arg;
 		ifc = rtnet_get_arg(fd, &_ifc, u_ifc, sizeof(_ifc));
 		if (IS_ERR(ifc))
@@ -288,8 +291,13 @@ int rt_socket_if_ioctl(struct rtdm_fd *fd, int request, void __user * arg)
 		}
 
 		return rtnet_put_arg(fd, &u_ifc->ifc_len, &size, sizeof(size));
+	    }
+
+	case SIOCSIFVLAN:
+	  return rtvlan_ioctl_handler(arg);
 	}
 
+
 	u_ifr = arg;
 	ifr = rtnet_get_arg(fd, &_ifr, u_ifr, sizeof(_ifr));
 	if (IS_ERR(ifr))
@@ -316,10 +324,8 @@ int rt_socket_if_ioctl(struct rtdm_fd *fd, int request, void __user * arg)
 	case SIOCGIFFLAGS:
 		flags = rtdev->flags;
 		if ((ifr->ifr_flags & IFF_UP)
-		    && (rtdev->link_state
-			& (RTNET_LINK_STATE_PRESENT
-			   | RTNET_LINK_STATE_NOCARRIER))
-		    == RTNET_LINK_STATE_PRESENT)
+		    && rtnetif_carrier_ok(rtdev)
+		    && rtnetif_device_present(rtdev))
 			flags |= IFF_RUNNING;
 		ret = rtnet_put_arg(fd, &u_ifr->ifr_flags, &flags,
 				    sizeof(u_ifr->ifr_flags));
diff --git a/kernel/drivers/net/stack/vlan.c b/kernel/drivers/net/stack/vlan.c
new file mode 100644
index 000000000..7e8c389a4
--- /dev/null
+++ b/kernel/drivers/net/stack/vlan.c
@@ -0,0 +1,725 @@
+/*
+ * INET		802.1Q VLAN
+ *		Ethernet-type device handling.
+ *
+ * Authors:	Ben Greear <greearb@candelatech.com>
+ *		Please send support related email to: netdev@vger.kernel.org
+ *		VLAN Home Page: http://www.candelatech.com/~greear/vlan.html
+ *
+ * Fixes:
+ *		Fix for packet capture - Nick Eggleston <nick@dccinc.com>;
+ *		Add HW acceleration hooks - David S. Miller <davem@redhat.com>;
+ *		Correct all the locking - David S. Miller <davem@redhat.com>;
+ *		Use hash table for VLAN groups - David S. Miller <davem@redhat.com>
+ *
+ *		This program is free software; you can redistribute it and/or
+ *		modify it under the terms of the GNU General Public License
+ *		as published by the Free Software Foundation; either version
+ *		2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+
+#include <rtdev.h>
+#include <rtnet_port.h>
+#include <rtif_vlan.h>
+
+static unsigned short rtvlan_name_type = VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD;
+
+struct rtnet_device *__rtdev_real_dev(struct rtnet_device *dev)
+{
+	if (is_rtvlan_dev(dev))
+		dev = rtvlan_dev_priv(dev)->real_dev;
+
+	return dev;
+}
+EXPORT_SYMBOL_GPL(__rtdev_real_dev);
+
+static inline u16 rtvlan_dev_vlan_id(const struct rtnet_device *dev)
+{
+	return rtvlan_dev_priv(dev)->vlan_id;
+}
+
+static void vlan_dev_set_rx_mode(struct rtnet_device *vlan_dev)
+{
+	struct rtvlan_dev_priv *vlan = rtvlan_dev_priv(vlan_dev);
+	struct rtnet_device *real_dev = vlan->real_dev;
+
+	rt_dev_mc_upload(real_dev);
+}
+
+/*
+ *	Create the VLAN header for an arbitrary protocol layer
+ *
+ *	saddr=NULL	means use device source address
+ *	daddr=NULL	means leave destination address (eg unresolved arp)
+ *
+ *  This is called when the SKB is moving down the stack towards the
+ *  physical devices.
+ */
+static int vlan_dev_hard_header(struct rtskb *skb, struct rtnet_device *dev,
+				unsigned short type,
+				void *daddr, void *saddr,
+				unsigned int len)
+{
+	struct rtvlan_dev_priv *vlan = rtvlan_dev_priv(dev);
+	struct vlan_hdr *vhdr;
+	unsigned int vhdrlen = 0;
+	u16 vlan_tci = 0;
+	int rc;
+
+	if (!(vlan->flags & VLAN_FLAG_REORDER_HDR)) {
+		vhdr = (struct vlan_hdr *) rtskb_push(skb, VLAN_HLEN);
+
+		vlan_tci = vlan->vlan_id;
+		vlan_tci |= rtvlan_dev_get_egress_qos_mask(dev, skb->priority);
+		vhdr->h_vlan_TCI = htons(vlan_tci);
+
+		/*
+		 *  Set the protocol type. For a packet of type ETH_P_802_3/2 we
+		 *  put the length in here instead.
+		 */
+		if (type != ETH_P_802_3 && type != ETH_P_802_2)
+			vhdr->h_vlan_encapsulated_proto = htons(type);
+		else
+			vhdr->h_vlan_encapsulated_proto = htons(len);
+
+		skb->protocol = vlan->vlan_proto;
+		type = ntohs(vlan->vlan_proto);
+		vhdrlen = VLAN_HLEN;
+	}
+
+	/* Before delegating work to the lower layer, enter our MAC-address */
+	if (saddr == NULL)
+		saddr = dev->dev_addr;
+
+	/* Now make the underlying real hard header */
+	dev = vlan->real_dev;
+	rc = dev->hard_header(skb, dev, type, daddr, saddr, len + vhdrlen);
+	if (rc > 0)
+		rc += vhdrlen;
+	return rc;
+}
+
+static netdev_tx_t vlan_dev_hard_start_xmit(struct rtskb *skb,
+					    struct rtnet_device *dev)
+{
+	struct rtvlan_dev_priv *vlan = rtvlan_dev_priv(dev);
+	struct vlan_ethhdr *veth = (struct vlan_ethhdr *)skb->data;
+	struct rtnet_device *real_dev = vlan->real_dev;
+	unsigned int len;
+	int ret;
+
+	/* Handle non-VLAN frames if they are sent to us, for example by DHCP.
+	 *
+	 * NOTE: THIS ASSUMES DIX ETHERNET, SPECIFICALLY NOT SUPPORTING
+	 * OTHER THINGS LIKE FDDI/TokenRing/802.3 SNAPs...
+	 */
+	if (veth->h_vlan_proto != vlan->vlan_proto ||
+		(vlan->flags & VLAN_FLAG_REORDER_HDR)) {
+		u16 vlan_tci;
+		vlan_tci = vlan->vlan_id;
+		vlan_tci |= rtvlan_dev_get_egress_qos_mask(dev, skb->priority);
+		rtvlan_put_tag(skb, vlan->vlan_proto, vlan_tci);
+	}
+
+	skb->rtdev = real_dev;
+	len = skb->len;
+
+	ret = real_dev->start_xmit(skb, real_dev);
+
+	if (likely(ret == 0)) {
+		struct rtvlan_pcpu_stats *stats;
+
+		stats = this_cpu_ptr(vlan->vlan_pcpu_stats);
+		raw_write_seqcount_begin(&stats->syncp);
+		stats->tx_packets++;
+		stats->tx_bytes += len;
+		raw_write_seqcount_end(&stats->syncp);
+	} else {
+		this_cpu_inc(vlan->vlan_pcpu_stats->tx_dropped);
+	}
+
+	return ret;
+}
+
+void vlan_dev_set_ingress_priority(const struct rtnet_device *dev,
+				   u32 skb_prio, u16 vlan_prio)
+{
+	struct rtvlan_dev_priv *vlan = rtvlan_dev_priv(dev);
+
+	if (vlan->ingress_priority_map[vlan_prio & 0x7] && !skb_prio)
+		vlan->nr_ingress_mappings--;
+	else if (!vlan->ingress_priority_map[vlan_prio & 0x7] && skb_prio)
+		vlan->nr_ingress_mappings++;
+
+	vlan->ingress_priority_map[vlan_prio & 0x7] = skb_prio;
+}
+
+int vlan_dev_set_egress_priority(const struct rtnet_device *dev,
+				 u32 skb_prio, u16 vlan_prio)
+{
+	struct rtvlan_dev_priv *vlan = rtvlan_dev_priv(dev);
+	struct vlan_priority_tci_mapping *mp = NULL;
+	struct vlan_priority_tci_mapping *np;
+	u32 vlan_qos = (vlan_prio << VLAN_PRIO_SHIFT) & VLAN_PRIO_MASK;
+
+	/* See if a priority mapping exists.. */
+	mp = vlan->egress_priority_map[skb_prio & 0xF];
+	while (mp) {
+		if (mp->priority == skb_prio) {
+			if (mp->vlan_qos && !vlan_qos)
+				vlan->nr_egress_mappings--;
+			else if (!mp->vlan_qos && vlan_qos)
+				vlan->nr_egress_mappings++;
+			mp->vlan_qos = vlan_qos;
+			return 0;
+		}
+		mp = mp->next;
+	}
+
+	/* Create a new mapping then. */
+	mp = vlan->egress_priority_map[skb_prio & 0xF];
+	np = kmalloc(sizeof(struct vlan_priority_tci_mapping), GFP_KERNEL);
+	if (!np)
+		return -ENOBUFS;
+
+	np->next = mp;
+	np->priority = skb_prio;
+	np->vlan_qos = vlan_qos;
+	/* Before inserting this element in hash table, make sure all its fields
+	 * are committed to memory.
+	 * coupled with smp_rmb() in vlan_dev_get_egress_qos_mask()
+	 */
+	smp_wmb();
+	vlan->egress_priority_map[skb_prio & 0xF] = np;
+	if (vlan_qos)
+		vlan->nr_egress_mappings++;
+	return 0;
+}
+
+static inline u32 vlan_get_ingress_priority(struct rtnet_device *dev,
+					    u16 vlan_tci)
+{
+	struct rtvlan_dev_priv *vip = rtvlan_dev_priv(dev);
+
+	return vip->ingress_priority_map[(vlan_tci >> VLAN_PRIO_SHIFT) & 0x7];
+}
+
+/* Flags are defined in the vlan_flags enum in include/linux/if_vlan.h file. */
+static int
+vlan_dev_change_flags(const struct rtnet_device *dev, u32 flags, u32 mask)
+{
+	struct rtvlan_dev_priv *vlan = rtvlan_dev_priv(dev);
+	u32 old_flags = vlan->flags;
+
+	if (mask & ~(VLAN_FLAG_REORDER_HDR | VLAN_FLAG_LOOSE_BINDING))
+		return -EINVAL;
+
+	vlan->flags = (old_flags & ~mask) | (flags & mask);
+
+	return 0;
+}
+
+static void
+vlan_dev_get_realdev_name(const struct rtnet_device *dev, char *result)
+{
+	strncpy(result, rtvlan_dev_priv(dev)->real_dev->name, 23);
+}
+
+static int vlan_dev_open(struct rtnet_device *dev)
+{
+	struct rtvlan_dev_priv *vlan = rtvlan_dev_priv(dev);
+	struct rtnet_device *real_dev = vlan->real_dev;
+
+	if (!(real_dev->flags & IFF_UP) &&
+	    !(vlan->flags & VLAN_FLAG_LOOSE_BINDING))
+		return -ENETDOWN;
+
+	ether_addr_copy(vlan->real_dev_addr, real_dev->dev_addr);
+
+	vlan_dev_set_rx_mode(dev);
+
+	if (rtnetif_carrier_ok(real_dev))
+		rtnetif_carrier_on(dev);
+	return 0;
+}
+
+static int vlan_dev_stop(struct rtnet_device *dev)
+{
+	rtnetif_carrier_off(dev);
+	return 0;
+}
+
+static struct net_device_stats *vlan_dev_get_stats(struct rtnet_device *dev)
+{
+	struct rtvlan_dev_priv *vlan = rtvlan_dev_priv(dev);
+	struct net_device_stats *stats = &vlan->stats;
+
+	memset(stats, '\0', sizeof(*stats));
+
+	if (rtvlan_dev_priv(dev)->vlan_pcpu_stats) {
+		struct rtvlan_pcpu_stats *p;
+		u32 rx_errors = 0, tx_dropped = 0;
+		int i;
+
+		for_each_possible_cpu(i) {
+			u64 rxpackets, rxbytes, rxmulticast, txpackets, txbytes;
+			unsigned int start;
+
+			p = per_cpu_ptr(rtvlan_dev_priv(dev)->vlan_pcpu_stats, i);
+			do {
+				start = raw_seqcount_begin(&p->syncp);
+				rxpackets	= p->rx_packets;
+				rxbytes		= p->rx_bytes;
+				rxmulticast	= p->rx_multicast;
+				txpackets	= p->tx_packets;
+				txbytes		= p->tx_bytes;
+			} while (read_seqcount_retry(&p->syncp, start));
+
+			stats->rx_packets	+= rxpackets;
+			stats->rx_bytes		+= rxbytes;
+			stats->multicast	+= rxmulticast;
+			stats->tx_packets	+= txpackets;
+			stats->tx_bytes		+= txbytes;
+			/* rx_errors & tx_dropped are u32 */
+			rx_errors	+= p->rx_errors;
+			tx_dropped	+= p->tx_dropped;
+		}
+		stats->rx_errors  = rx_errors;
+		stats->tx_dropped = tx_dropped;
+	}
+	return stats;
+}
+
+static int vlan_dev_init(struct rtnet_device *dev)
+{
+	struct rtvlan_dev_priv *vlan = rtvlan_dev_priv(dev);
+	struct rtnet_device *real_dev = vlan->real_dev;
+	int i;
+
+	rtnetif_carrier_off(dev);
+
+	/* IFF_BROADCAST|IFF_MULTICAST; ??? */
+	dev->flags  = real_dev->flags & ~(IFF_UP | IFF_PROMISC | IFF_ALLMULTI
+					| IFF_MASTER | IFF_SLAVE);
+	dev->link_state	 =
+		(real_dev->link_state & (1<<__RTNET_LINK_STATE_NOCARRIER)) |
+		(1<<__RTNET_LINK_STATE_PRESENT);
+
+	dev->features = NETIF_F_LLTX;
+
+	if (is_zero_ether_addr(dev->dev_addr))
+		ether_addr_copy(dev->dev_addr, real_dev->dev_addr);;
+	if (is_zero_ether_addr(dev->broadcast))
+		memcpy(dev->broadcast, real_dev->broadcast, dev->addr_len);
+
+	dev->open = vlan_dev_open;
+	dev->stop = vlan_dev_stop;
+	dev->hard_header_len = real_dev->hard_header_len + VLAN_HLEN;
+	dev->hard_header = vlan_dev_hard_header;
+	dev->hard_start_xmit = vlan_dev_hard_start_xmit;
+	dev->get_stats = vlan_dev_get_stats;
+	if (real_dev->set_multicast_list)
+		dev->set_multicast_list = vlan_dev_set_rx_mode;
+
+	vlan->vlan_pcpu_stats = alloc_percpu(typeof(*vlan->vlan_pcpu_stats));
+	if (!rtvlan_dev_priv(dev)->vlan_pcpu_stats)
+		return -ENOMEM;
+
+	for_each_possible_cpu(i) {
+		struct rtvlan_pcpu_stats *vlan_stat;
+		vlan_stat = per_cpu_ptr(vlan->vlan_pcpu_stats, i);
+		seqcount_init(&vlan_stat->syncp);
+	}
+
+	return 0;
+}
+
+static void vlan_dev_uninit(struct rtnet_device *dev)
+{
+	struct vlan_priority_tci_mapping *pm;
+	struct rtvlan_dev_priv *vlan = rtvlan_dev_priv(dev);
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(vlan->egress_priority_map); i++) {
+		while ((pm = vlan->egress_priority_map[i]) != NULL) {
+			vlan->egress_priority_map[i] = pm->next;
+			kfree(pm);
+		}
+	}
+}
+
+static void vlan_dev_free(struct rtnet_device *dev)
+{
+	struct rtvlan_dev_priv *vlan = rtvlan_dev_priv(dev);
+
+	vlan_dev_uninit(dev);
+	free_percpu(vlan->vlan_pcpu_stats);
+	vlan->vlan_pcpu_stats = NULL;
+	rt_unregister_rtnetdev(dev);
+	rt_rtdev_disconnect(dev);
+	rtdev_free(dev);
+}
+
+static bool vlan_hw_filter_capable(const struct rtnet_device *dev)
+{
+	return !!(dev->features & NETIF_F_HW_VLAN_CTAG_FILTER);
+}
+
+static struct rtnet_device *__rtvlan_find_dev(struct rtnet_device *dev, u16 vid)
+{
+	struct rtnet_device *vlan_dev;
+
+	if (vid == 0)
+		return dev;
+
+	list_for_each_entry(vlan_dev, &dev->vlan_link, vlan_link) {
+		struct rtvlan_dev_priv *vlan = rtvlan_dev_priv(vlan_dev);
+
+		if (vlan->vlan_id == vid)
+			return vlan_dev;
+	}
+
+	return NULL;
+}
+
+static struct rtnet_device *rtvlan_find_dev(struct rtnet_device *dev, u16 vid)
+{
+	struct rtnet_device *vlan_dev;
+	unsigned long flags;
+
+	rtdm_lock_get_irqsave(&dev->rtdev_lock, flags);
+	vlan_dev = __rtvlan_find_dev(dev, vid);
+	if (vlan_dev)
+		rtdev_reference(vlan_dev);
+	rtdm_lock_put_irqrestore(&dev->rtdev_lock, flags);
+
+	return vlan_dev;
+}
+
+static int rtvlan_vid_add(struct rtnet_device *dev)
+{
+	struct rtvlan_dev_priv *vlan = rtvlan_dev_priv(dev);
+	struct rtnet_device *real_dev = vlan->real_dev;
+	u16 vid = vlan->vlan_id;
+	unsigned long flags;
+	int err = 0;
+
+	rtdm_lock_get_irqsave(&dev->rtdev_lock, flags);
+	if (__rtvlan_find_dev(real_dev, vid)) {
+		err = -EEXIST;
+		goto out;
+	}
+
+	list_add(&dev->vlan_link, &real_dev->vlan_link);
+
+	if (vlan_hw_filter_capable(real_dev))
+		real_dev->vlan_rx_add_vid(real_dev, vid);
+  out:
+	rtdm_lock_put_irqrestore(&dev->rtdev_lock, flags);
+
+	return err;
+}
+
+static void rtvlan_vid_del(struct rtnet_device *dev)
+{
+	struct rtvlan_dev_priv *vlan = rtvlan_dev_priv(dev);
+	struct rtnet_device *real_dev = vlan->real_dev;
+	u16 vid = vlan->vlan_id;
+	unsigned long flags;
+
+	rtdm_lock_get_irqsave(&dev->rtdev_lock, flags);
+	if (__rtvlan_find_dev(real_dev, vid) != dev)
+		goto out;
+
+	list_del(&dev->vlan_link);
+
+	if (vlan_hw_filter_capable(real_dev))
+		real_dev->vlan_rx_kill_vid(real_dev, vid);
+  out:
+	rtdm_lock_put_irqrestore(&dev->rtdev_lock, flags);
+}
+
+void unregister_vlan_dev(struct rtnet_device *dev)
+{
+	struct rtvlan_dev_priv *vlan = rtvlan_dev_priv(dev);
+	struct rtnet_device *real_dev = vlan->real_dev;
+	u16 vlan_id = vlan->vlan_id;
+
+	if (vlan_id)
+		rtvlan_vid_del(dev);
+
+	/* Get rid of the vlan's reference to real_dev */
+	rtdev_dereference(real_dev);
+	vlan_dev_free(dev);
+}
+
+
+/*  Attach a VLAN device to a mac address (ie Ethernet Card).
+ *  Returns 0 if the device was created or a negative error code otherwise.
+ */
+static int register_vlan_device(struct rtnet_device *real_dev, u16 vlan_id)
+{
+	struct rtnet_device *new_dev;
+	struct rtvlan_dev_priv *vlan;
+	char name[IFNAMSIZ];
+	int err;
+
+	if (vlan_id >= VLAN_VID_MASK)
+		return -ERANGE;
+
+	/* Gotta set up the fields for the device.
+	   Only one type of device name supported
+	 */
+	switch (rtvlan_name_type) {
+	case VLAN_NAME_TYPE_RAW_PLUS_VID:
+		/* name will look like:	 eth1.0005 */
+		snprintf(name, IFNAMSIZ, "%s.%.4i", real_dev->name, vlan_id);
+		break;
+	case VLAN_NAME_TYPE_PLUS_VID_NO_PAD:
+		/* Put our vlan.VID in the name.
+		 * Name will look like:	 vlan5
+		 */
+		snprintf(name, IFNAMSIZ, "rtvlan%i", vlan_id);
+		break;
+	case VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD:
+		/* Put our vlan.VID in the name.
+		 * Name will look like:	 eth0.5
+		 */
+		snprintf(name, IFNAMSIZ, "%s.%i", real_dev->name, vlan_id);
+		break;
+	case VLAN_NAME_TYPE_PLUS_VID:
+		/* Put our vlan.VID in the name.
+		 * Name will look like:	 vlan0005
+		 */
+	default:
+		snprintf(name, IFNAMSIZ, "rtvlan%.4i", vlan_id);
+	}
+
+	rtdev_reference(real_dev);
+
+	new_dev = rt_alloc_etherdev(sizeof(struct rtvlan_dev_priv), 0);
+	if (new_dev == NULL) {
+		err = -ENOBUFS;
+		goto err;
+	}
+	rtdev_alloc_name(new_dev, name);
+	rt_rtdev_connect(new_dev, &RTDEV_manager);
+	new_dev->vers = RTDEV_VERS_2_0;
+
+	new_dev->priv_flags |= IFF_802_1Q_VLAN;
+	new_dev->priv_flags &= ~(IFF_XMIT_DST_RELEASE | IFF_TX_SKB_SHARING);
+
+	memset(new_dev->broadcast, 0, ETH_ALEN);
+
+	/* need 4 bytes for extra VLAN header info,
+	 * hope the underlying device can handle it.
+	 */
+	new_dev->mtu = real_dev->mtu;
+	new_dev->priv_flags |= (real_dev->priv_flags & IFF_UNICAST_FLT);
+
+	vlan = rtvlan_dev_priv(new_dev);
+	vlan->vlan_proto = htons(ETH_P_8021Q);
+	vlan->vlan_id = vlan_id;
+	vlan->real_dev = real_dev;
+	vlan->flags = VLAN_FLAG_REORDER_HDR;
+
+	err = vlan_dev_init(new_dev);
+	if (err < 0)
+		goto out_free_newdev;
+
+	err = rtvlan_vid_add(new_dev);
+	if (err < 0)
+		goto out_free_newdev;
+
+	err = rt_register_rtnetdev(new_dev);
+	if (err > 0) {
+		err = -err;
+		goto out_free_newdev;
+	}
+
+	return 0;
+
+out_free_newdev:
+	rt_rtdev_disconnect(new_dev);
+	rtdev_free(new_dev);
+  err:
+	rtdev_dereference(real_dev);
+	return err;
+}
+
+/*
+ *	VLAN IOCTL handler.
+ *	o execute requested action or pass command to the device driver
+ *   arg is really a struct vlan_ioctl_args __user *.
+ */
+int rtvlan_ioctl_handler(void __user *arg)
+{
+	int err;
+	struct vlan_ioctl_args args;
+	struct rtnet_device *dev = NULL;
+
+	if (copy_from_user(&args, arg, sizeof(args)))
+		return -EFAULT;
+
+	/* Null terminate this sucker, just in case. */
+	args.device1[23] = 0;
+	args.u.device2[23] = 0;
+
+	switch (args.cmd) {
+	case SET_VLAN_INGRESS_PRIORITY_CMD:
+	case SET_VLAN_EGRESS_PRIORITY_CMD:
+	case SET_VLAN_FLAG_CMD:
+	case ADD_VLAN_CMD:
+	case DEL_VLAN_CMD:
+	case GET_VLAN_REALDEV_NAME_CMD:
+	case GET_VLAN_VID_CMD:
+		err = -ENODEV;
+		dev = rtdev_get_by_name(args.device1);
+		if (!dev)
+			goto out;
+
+		err = -EINVAL;
+		if (args.cmd != ADD_VLAN_CMD && !is_rtvlan_dev(dev))
+			goto out;
+	}
+
+	switch (args.cmd) {
+	case SET_VLAN_INGRESS_PRIORITY_CMD:
+		err = -EPERM;
+		vlan_dev_set_ingress_priority(dev,
+					      args.u.skb_priority,
+					      args.vlan_qos);
+		err = 0;
+		break;
+
+	case SET_VLAN_EGRESS_PRIORITY_CMD:
+		err = -EPERM;
+		err = vlan_dev_set_egress_priority(dev,
+						   args.u.skb_priority,
+						   args.vlan_qos);
+		break;
+
+	case SET_VLAN_FLAG_CMD:
+		err = -EPERM;
+		err = vlan_dev_change_flags(dev,
+					    args.vlan_qos ? args.u.flag : 0,
+					    args.u.flag);
+		break;
+
+	case SET_VLAN_NAME_TYPE_CMD:
+		err = -EPERM;
+		if ((args.u.name_type >= 0) &&
+		    (args.u.name_type < VLAN_NAME_TYPE_HIGHEST)) {
+			rtvlan_name_type = args.u.name_type;
+			err = 0;
+		} else {
+			err = -EINVAL;
+		}
+		break;
+
+	case ADD_VLAN_CMD:
+		err = -EPERM;
+		err = register_vlan_device(dev, args.u.VID);
+		break;
+
+	case DEL_VLAN_CMD:
+		err = -EPERM;
+		rtdev_dereference(dev); /*
+					 * Must dereference before unregistering
+					 * in order to avoid infinite loop in
+					 * rt_unregister_rtnetdev
+					 */
+		unregister_vlan_dev(dev);
+		return 0;
+
+	case GET_VLAN_REALDEV_NAME_CMD:
+		err = 0;
+		vlan_dev_get_realdev_name(dev, args.u.device2);
+		if (copy_to_user(arg, &args,
+				 sizeof(struct vlan_ioctl_args)))
+			err = -EFAULT;
+		break;
+
+	case GET_VLAN_VID_CMD:
+		err = 0;
+		args.u.VID = rtvlan_dev_vlan_id(dev);
+		if (copy_to_user(arg, &args,
+				 sizeof(struct vlan_ioctl_args)))
+		      err = -EFAULT;
+		break;
+
+	default:
+		err = -EOPNOTSUPP;
+		break;
+	}
+out:
+	if (dev)
+		rtdev_dereference(dev);
+
+	return err;
+}
+
+int rtvlan_proto_rx(struct rtskb *skb, struct rtpacket_type *pt)
+{
+	struct vlan_ethhdr *veth = (struct vlan_ethhdr *)skb->mac.raw;
+	struct rtvlan_pcpu_stats *rx_stats;
+	struct rtnet_device *vlan_dev;
+	struct rtvlan_dev_priv *vlan;
+	u16 vlan_tci;
+
+	vlan_tci = ntohs(veth->h_vlan_TCI);
+	vlan_dev = rtvlan_find_dev(skb->rtdev, vlan_tci & VLAN_VID_MASK);
+	if (!vlan_dev) {
+		kfree_rtskb(skb);
+		rtdev_dereference(skb->rtdev);
+		return 0;
+	}
+	vlan = rtvlan_dev_priv(vlan_dev);
+
+	skb->priority = vlan_get_ingress_priority(vlan_dev, vlan_tci);
+	skb->protocol = veth->h_vlan_encapsulated_proto;
+	skb->rtdev = vlan_dev;
+
+	if (skb->pkt_type == PACKET_OTHERHOST
+		&& ether_addr_equal(veth->h_dest, vlan_dev->dev_addr))
+		skb->pkt_type = PACKET_HOST;
+
+	if (vlan->flags & VLAN_FLAG_REORDER_HDR) {
+		memmove(skb->mac.raw + VLAN_HLEN, skb->mac.raw, 2 * ETH_ALEN);
+#ifdef CONFIG_XENO_DRIVERS_NET_ADDON_RTCAP
+		skb->cap_start += VLAN_HLEN;
+		skb->cap_len -= VLAN_HLEN;
+#endif
+	}
+	rtskb_pull(skb, VLAN_HLEN);
+
+	rx_stats = this_cpu_ptr(rtvlan_dev_priv(vlan_dev)->vlan_pcpu_stats);
+
+	raw_write_seqcount_begin(&rx_stats->syncp);
+	rx_stats->rx_packets++;
+	rx_stats->rx_bytes += skb->len;
+	if (skb->pkt_type == PACKET_MULTICAST)
+		rx_stats->rx_multicast++;
+	raw_write_seqcount_end(&rx_stats->syncp);
+
+	rt_stack_deliver(skb);
+	return 0;
+}
+
+struct rtpacket_type rtvlan_packet_type = {
+	.type = __constant_htons(ETH_P_8021Q),
+	.handler = rtvlan_proto_rx,
+};
+
+void rtvlan_proto_init(void)
+{
+	rtdev_add_pack(&rtvlan_packet_type);
+}
+
+void rtvlan_proto_release(void)
+{
+	rtdev_remove_pack(&rtvlan_packet_type);
+}
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH 05/16] utils/net: add VLAN filter configuration tool
  2019-03-21 17:13 [PATCH 00/16] multicast, VLAN support for RTnet Philippe Gerum
                   ` (3 preceding siblings ...)
  2019-03-21 17:13 ` [PATCH 04/16] net/stack: add support for VLAN filtering Philippe Gerum
@ 2019-03-21 17:13 ` Philippe Gerum
  2019-03-21 17:13 ` [PATCH 06/16] net/udp: allow retrieving irq timestamp with SIOCGSTAMP ioctl Philippe Gerum
                   ` (10 subsequent siblings)
  15 siblings, 0 replies; 19+ messages in thread
From: Philippe Gerum @ 2019-03-21 17:13 UTC (permalink / raw)
  To: xenomai; +Cc: Gilles Chanteperdrix, Philippe Gerum

From: Gilles Chanteperdrix <gilles.chanteperdrix@xenomai.org>

Signed-off-by: Philippe Gerum <rpm@xenomai.org>
---
 utils/net/Makefile.am |   1 +
 utils/net/rtvconfig.c | 257 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 258 insertions(+)
 create mode 100644 utils/net/rtvconfig.c

diff --git a/utils/net/Makefile.am b/utils/net/Makefile.am
index 3b90f8adf..90e9002ea 100644
--- a/utils/net/Makefile.am
+++ b/utils/net/Makefile.am
@@ -11,6 +11,7 @@ sbin_PROGRAMS = \
 	rtcfg \
 	rtifconfig \
 	rtiwconfig \
+	rtvconfig \
 	rtping  \
 	rtroute \
 	tdmacfg
diff --git a/utils/net/rtvconfig.c b/utils/net/rtvconfig.c
new file mode 100644
index 000000000..281e93422
--- /dev/null
+++ b/utils/net/rtvconfig.c
@@ -0,0 +1,257 @@
+//
+//Copyright (C) 2001  Ben Greear
+//
+//This program is free software; you can redistribute it and/or
+//modify it under the terms of the GNU Library General Public License
+//as published by the Free Software Foundation; either version 2
+//of the License, or (at your option) any later version.
+//
+//This program 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 General Public License for more details.
+//
+//You should have received a copy of the GNU Library General Public License
+//along with this program; if not, write to the Free Software
+//Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+//
+// To contact the Author, Ben Greear:  greearb@candelatech.com
+//
+
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <strings.h>
+#include <sys/ioctl.h>
+#include <linux/if_vlan.h>
+#include <linux/sockios.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+
+
+#define MAX_HOSTNAME 256
+
+
+static char* usage =
+      "\n"
+"Usage: add             [interface-name] [vlan_id]\n"
+"       rem             [vlan-name]\n"
+"       set_flag        [interface-name] [flag-num]       [0 | 1]\n"
+"       set_egress_map  [vlan-name]      [skb_priority]   [vlan_qos]\n"
+"       set_ingress_map [vlan-name]      [skb_priority]   [vlan_qos]\n"
+"       set_name_type   [name-type]\n"
+"\n"
+"* The [interface-name] is the name of the ethernet card that hosts\n"
+"  the VLAN you are talking about.\n"
+"* The vlan_id is the identifier (0-4095) of the VLAN you are operating on.\n"
+"* skb_priority is the priority in the socket buffer (sk_buff).\n"
+"* vlan_qos is the 3 bit priority in the VLAN header\n"
+"* name-type:  VLAN_PLUS_VID (vlan0005), VLAN_PLUS_VID_NO_PAD (vlan5),\n"
+"              DEV_PLUS_VID (eth0.0005), DEV_PLUS_VID_NO_PAD (eth0.5)\n"
+"* bind-type:  PER_DEVICE  # Allows vlan 5 on eth0 and eth1 to be unique.\n"
+"              PER_KERNEL  # Forces vlan 5 to be unique across all devices.\n"
+"* FLAGS:  1 REORDER_HDR  When this is set, the VLAN device will move the\n"
+"            ethernet header around to make it look exactly like a real\n"
+"            ethernet device.  This may help programs such as DHCPd which\n"
+"            read the raw ethernet packet and make assumptions about the\n"
+"            location of bytes.  If you don't need it, don't turn it on, because\n"
+"            there will be at least a small performance degradation.  Default\n"
+"            is OFF.\n";
+
+void show_usage() {
+   fprintf(stdout,usage);
+}
+
+int hex_to_bytes(char* bytes, int bytes_length, char* hex_str) {
+   int hlen;
+   int i;
+
+   int j = 0;
+   char hex[3];
+   char* stop; /* not used for any real purpose */
+
+   hlen = strlen(hex_str);
+
+   hex[2] = 0;
+
+   for (i = 0; i<hlen; i++) {
+
+      hex[0] = hex_str[i];
+      i++;
+      if (i >= hlen) {
+	 return j; /* done */
+      }
+
+      hex[1] = hex_str[i];
+      bytes[j++] = (char)strtoul(hex, &stop, 16);
+   }
+   return j;
+}
+
+
+int main(int argc, char** argv) {
+   int fd;
+   struct vlan_ioctl_args if_request;
+
+   char* cmd = NULL;
+   char* if_name = NULL;
+   unsigned int vid = 0;
+   unsigned int skb_priority;
+   unsigned short vlan_qos;
+   unsigned int nm_type = VLAN_NAME_TYPE_PLUS_VID;
+
+   memset(&if_request, 0, sizeof(struct vlan_ioctl_args));
+
+   if ((argc < 3) || (argc > 5)) {
+      fprintf(stdout,"Expecting argc to be 3-5, inclusive.  Was: %d\n",argc);
+
+      show_usage();
+      exit(1);
+   }
+   else {
+      cmd = argv[1];
+
+      if (strcasecmp(cmd, "set_name_type") == 0) {
+	 if (strcasecmp(argv[2], "VLAN_PLUS_VID") == 0) {
+	    nm_type = VLAN_NAME_TYPE_PLUS_VID;
+	 }
+	 else if (strcasecmp(argv[2], "VLAN_PLUS_VID_NO_PAD") == 0) {
+	    nm_type = VLAN_NAME_TYPE_PLUS_VID_NO_PAD;
+	 }
+	 else if (strcasecmp(argv[2], "DEV_PLUS_VID") == 0) {
+	    nm_type = VLAN_NAME_TYPE_RAW_PLUS_VID;
+	 }
+	 else if (strcasecmp(argv[2], "DEV_PLUS_VID_NO_PAD") == 0) {
+	    nm_type = VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD;
+	 }
+	 else {
+	    // MATHIEU
+	    //cerr << "Invalid name type.\n";
+	    fprintf(stderr,"Invalid name type.\n");
+
+	    show_usage();
+	    exit(1);
+	 }
+	 if_request.u.name_type = nm_type;
+      }
+      else {
+	 if_name = argv[2];
+	 if (strlen(if_name) > 15) {
+	    // MATHIEU
+	    //cerr << "ERROR:  if_name must be 15 characters or less." << endl;
+	    fprintf(stderr,"ERROR:  if_name must be 15 characters or less.\n");
+	    exit(1);
+	 }
+	 strcpy(if_request.device1, if_name);
+      }
+
+      if (argc == 4) {
+	 vid = atoi(argv[3]);
+	 if_request.u.VID = vid;
+      }
+
+      if (argc == 5) {
+	 skb_priority = atoi(argv[3]);
+	 vlan_qos = atoi(argv[4]);
+	 if_request.u.skb_priority = skb_priority;
+	 if_request.vlan_qos = vlan_qos;
+      }
+   }
+
+   /* We use sockets now, instead of the file descriptor */
+   if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+      fprintf(stderr, "FATAL:  Couldn't open a socket..go figure!\n");
+      exit(2);
+   }
+
+   /* add */
+   if (strcasecmp(cmd, "add") == 0) {
+      if_request.cmd = ADD_VLAN_CMD;
+      if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
+	 fprintf(stderr,"ERROR: trying to add VLAN #%u to IF -:%s:-  error: %s\n",
+		    vid, if_name, strerror(errno));
+	 exit(3);
+      }
+      else {
+	 fprintf(stdout,"Added VLAN with VID == %u to IF -:%s:-\n",
+		 vid, if_name);
+	 if (vid == 1) {
+	    fprintf(stdout, "WARNING:  VLAN 1 does not work with many switches,\nconsider another number if you have problems.\n");
+	 }
+      }
+   }//if
+   else if (strcasecmp(cmd, "rem") == 0) {
+      if_request.cmd = DEL_VLAN_CMD;
+      if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
+	 fprintf(stderr,"ERROR: trying to remove VLAN -:%s:- error: %s\n",
+		 if_name, strerror(errno));
+	 exit(4);
+      }
+      else {
+	 fprintf(stdout,"Removed VLAN -:%s:-\n", if_name);
+      }
+   }//if
+   else if (strcasecmp(cmd, "set_egress_map") == 0) {
+      if_request.cmd = SET_VLAN_EGRESS_PRIORITY_CMD;
+      if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
+	 fprintf(stderr,"ERROR: trying to set egress map on device -:%s:- error: %s\n",
+		 if_name, strerror(errno));
+	 exit(5);
+      }
+      else {
+	 fprintf(stdout,"Set egress mapping on device -:%s:- "
+		 "Should be visible in /proc/net/vlan/%s\n",
+		 if_name, if_name);
+      }
+   }
+   else if (strcasecmp(cmd, "set_ingress_map") == 0) {
+      if_request.cmd = SET_VLAN_INGRESS_PRIORITY_CMD;
+      if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
+	 fprintf(stderr,"ERROR: trying to set ingress map on device -:%s:- error: %s\n",
+		 if_name, strerror(errno));
+	 exit(6);
+      }
+      else {
+	 fprintf(stdout,"Set ingress mapping on device -:%s:- "
+		 "Should be visible in /proc/net/vlan/%s\n",
+		 if_name, if_name);
+      }
+   }
+   else if (strcasecmp(cmd, "set_flag") == 0) {
+      if_request.cmd = SET_VLAN_FLAG_CMD;
+      if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
+	 fprintf(stderr,"ERROR: trying to set flag on device -:%s:- error: %s\n",
+		 if_name, strerror(errno));
+	 exit(7);
+      }
+      else {
+	 fprintf(stdout,"Set flag on device -:%s:- "
+		 "Should be visible in /proc/net/vlan/%s\n",
+		 if_name, if_name);
+      }
+   }
+   else if (strcasecmp(cmd, "set_name_type") == 0) {
+      if_request.cmd = SET_VLAN_NAME_TYPE_CMD;
+      if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
+	 fprintf(stderr,"ERROR: trying to set name type for VLAN subsystem, error: %s\n",
+		 strerror(errno));
+	 exit(8);
+      }
+      else {
+	 fprintf(stdout,"Set name-type for VLAN subsystem."
+		 " Should be visible in /proc/net/vlan/config\n");
+      }
+   }
+   else {
+      fprintf(stderr, "Unknown command -:%s:-\n", cmd);
+
+      show_usage();
+      exit(5);
+   }
+
+   return 0;
+}/* main */
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH 06/16] net/udp: allow retrieving irq timestamp with SIOCGSTAMP ioctl
  2019-03-21 17:13 [PATCH 00/16] multicast, VLAN support for RTnet Philippe Gerum
                   ` (4 preceding siblings ...)
  2019-03-21 17:13 ` [PATCH 05/16] utils/net: add VLAN filter configuration tool Philippe Gerum
@ 2019-03-21 17:13 ` Philippe Gerum
  2019-03-21 17:13 ` [PATCH 07/16] net/udp sendmsg: do not return an error if dest addr is null Philippe Gerum
                   ` (9 subsequent siblings)
  15 siblings, 0 replies; 19+ messages in thread
From: Philippe Gerum @ 2019-03-21 17:13 UTC (permalink / raw)
  To: xenomai; +Cc: Gilles Chanteperdrix, Philippe Gerum

From: Gilles Chanteperdrix <gilles.chanteperdrix@xenomai.org>

Signed-off-by: Philippe Gerum <rpm@xenomai.org>
---
 kernel/drivers/net/stack/include/rtnet_socket.h | 2 ++
 kernel/drivers/net/stack/ipv4/udp/udp.c         | 9 +++++++++
 2 files changed, 11 insertions(+)

diff --git a/kernel/drivers/net/stack/include/rtnet_socket.h b/kernel/drivers/net/stack/include/rtnet_socket.h
index dbf9b7c16..8fe128efd 100644
--- a/kernel/drivers/net/stack/include/rtnet_socket.h
+++ b/kernel/drivers/net/stack/include/rtnet_socket.h
@@ -80,6 +80,8 @@ struct rtsocket {
 		} packet;
 	} prot;
 
+	u64 timestamp;
+
 	struct module *owner;
 };
 
diff --git a/kernel/drivers/net/stack/ipv4/udp/udp.c b/kernel/drivers/net/stack/ipv4/udp/udp.c
index d4003d2ee..8539fe87a 100644
--- a/kernel/drivers/net/stack/ipv4/udp/udp.c
+++ b/kernel/drivers/net/stack/ipv4/udp/udp.c
@@ -361,6 +361,8 @@ int rt_udp_ioctl(struct rtdm_fd *fd, unsigned int request, void __user * arg)
 	struct rtsocket *sock = rtdm_fd_to_private(fd);
 	const struct _rtdm_setsockaddr_args *setaddr;
 	struct _rtdm_setsockaddr_args _setaddr;
+	unsigned long ns;
+	struct timeval tv;
 
 	/* fast path for common socket IOCTLs */
 	if (_IOC_TYPE(request) == RTIOC_TYPE_NETWORK)
@@ -379,6 +381,12 @@ int rt_udp_ioctl(struct rtdm_fd *fd, unsigned int request, void __user * arg)
 		return rt_udp_connect(fd, sock, setaddr->addr,
 				      setaddr->addrlen);
 
+	case SIOCGSTAMP:
+		tv.tv_sec = xnclock_divrem_billion(sock->timestamp, &ns);
+		tv.tv_usec = ns / 1000;
+
+		return copy_to_user(arg, &tv, sizeof(tv));
+
 	default:
 		return rt_ip_ioctl(fd, request, arg);
 	}
@@ -472,6 +480,7 @@ ssize_t rt_udp_recvmsg(struct rtdm_fd * fd, struct user_msghdr * u_msg,
 
 	/* iterate over all IP fragments */
 	do {
+		sock->timestamp = skb->time_stamp;
 		rtskb_trim(skb, data_len);
 
 		block_size = skb->len;
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH 07/16] net/udp sendmsg: do not return an error if dest addr is null
  2019-03-21 17:13 [PATCH 00/16] multicast, VLAN support for RTnet Philippe Gerum
                   ` (5 preceding siblings ...)
  2019-03-21 17:13 ` [PATCH 06/16] net/udp: allow retrieving irq timestamp with SIOCGSTAMP ioctl Philippe Gerum
@ 2019-03-21 17:13 ` Philippe Gerum
  2019-03-21 17:13 ` [PATCH 08/16] net/stack: rtskb: increase buffer size Philippe Gerum
                   ` (8 subsequent siblings)
  15 siblings, 0 replies; 19+ messages in thread
From: Philippe Gerum @ 2019-03-21 17:13 UTC (permalink / raw)
  To: xenomai; +Cc: Gilles Chanteperdrix, Philippe Gerum

From: Gilles Chanteperdrix <gilles.chanteperdrix@xenomai.org>

Signed-off-by: Philippe Gerum <rpm@xenomai.org>
---
 kernel/drivers/net/stack/ipv4/udp/udp.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/kernel/drivers/net/stack/ipv4/udp/udp.c b/kernel/drivers/net/stack/ipv4/udp/udp.c
index 8539fe87a..57b642e5c 100644
--- a/kernel/drivers/net/stack/ipv4/udp/udp.c
+++ b/kernel/drivers/net/stack/ipv4/udp/udp.c
@@ -701,6 +701,9 @@ ssize_t rt_udp_sendmsg(struct rtdm_fd * fd, const struct user_msghdr * msg,
 
 	rtdm_lock_put_irqrestore(&udp_socket_base_lock, context);
 
+	if (daddr == 0)
+		return 0;
+
 	if ((daddr | dport) == 0) {
 		err = -EINVAL;
 		goto out;
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH 08/16] net/stack: rtskb: increase buffer size
  2019-03-21 17:13 [PATCH 00/16] multicast, VLAN support for RTnet Philippe Gerum
                   ` (6 preceding siblings ...)
  2019-03-21 17:13 ` [PATCH 07/16] net/udp sendmsg: do not return an error if dest addr is null Philippe Gerum
@ 2019-03-21 17:13 ` Philippe Gerum
  2019-03-21 17:13 ` [PATCH 09/16] net/stack: manager: ratelimit printk when dropping buffers Philippe Gerum
                   ` (7 subsequent siblings)
  15 siblings, 0 replies; 19+ messages in thread
From: Philippe Gerum @ 2019-03-21 17:13 UTC (permalink / raw)
  To: xenomai; +Cc: Gilles Chanteperdrix, Philippe Gerum

From: Gilles Chanteperdrix <gilles.chanteperdrix@xenomai.org>

The largest packet size an IGB device can handle is 2k. Since we have
a fixed buffer size, we need to accomodate for this.

Signed-off-by: Philippe Gerum <rpm@xenomai.org>
---
 kernel/drivers/net/stack/include/rtskb.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/kernel/drivers/net/stack/include/rtskb.h b/kernel/drivers/net/stack/include/rtskb.h
index 36445ad08..55e3ded99 100644
--- a/kernel/drivers/net/stack/include/rtskb.h
+++ b/kernel/drivers/net/stack/include/rtskb.h
@@ -263,7 +263,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                  (2048 + NET_IP_ALIGN)    /* maximum needed by igb */
 
 extern unsigned int rtskb_pools;	/* current number of rtskb pools      */
 extern unsigned int rtskb_pools_max;	/* maximum number of rtskb pools      */
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH 09/16] net/stack: manager: ratelimit printk when dropping buffers
  2019-03-21 17:13 [PATCH 00/16] multicast, VLAN support for RTnet Philippe Gerum
                   ` (7 preceding siblings ...)
  2019-03-21 17:13 ` [PATCH 08/16] net/stack: rtskb: increase buffer size Philippe Gerum
@ 2019-03-21 17:13 ` Philippe Gerum
  2019-03-21 17:13 ` [PATCH 10/16] net/ipv4: icmp: forward unused packets to proxy Philippe Gerum
                   ` (6 subsequent siblings)
  15 siblings, 0 replies; 19+ messages in thread
From: Philippe Gerum @ 2019-03-21 17:13 UTC (permalink / raw)
  To: xenomai; +Cc: Gilles Chanteperdrix, Philippe Gerum

From: Gilles Chanteperdrix <gilles.chanteperdrix@xenomai.org>

Signed-off-by: Philippe Gerum <rpm@xenomai.org>
---
 kernel/drivers/net/stack/stack_mgr.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/kernel/drivers/net/stack/stack_mgr.c b/kernel/drivers/net/stack/stack_mgr.c
index 4059e7c4c..0e89900b5 100644
--- a/kernel/drivers/net/stack/stack_mgr.c
+++ b/kernel/drivers/net/stack/stack_mgr.c
@@ -113,7 +113,7 @@ void rtnetif_rx(struct rtskb *skb)
 	    );
 
 	if (unlikely(rtskb_fifo_insert_inirq(&rx.fifo, skb) < 0)) {
-		rtdm_printk("RTnet: dropping packet in %s()\n", __FUNCTION__);
+		rtdm_printk_ratelimited("RTnet: dropping packet in %s()\n", __FUNCTION__);
 		kfree_rtskb(skb);
 	}
 }
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH 10/16] net/ipv4: icmp: forward unused packets to proxy
  2019-03-21 17:13 [PATCH 00/16] multicast, VLAN support for RTnet Philippe Gerum
                   ` (8 preceding siblings ...)
  2019-03-21 17:13 ` [PATCH 09/16] net/stack: manager: ratelimit printk when dropping buffers Philippe Gerum
@ 2019-03-21 17:13 ` Philippe Gerum
  2019-03-21 17:13 ` [PATCH 11/16] net/drivers: e1000e: enable multicast Philippe Gerum
                   ` (5 subsequent siblings)
  15 siblings, 0 replies; 19+ messages in thread
From: Philippe Gerum @ 2019-03-21 17:13 UTC (permalink / raw)
  To: xenomai; +Cc: Gilles Chanteperdrix, Philippe Gerum

From: Gilles Chanteperdrix <gilles.chanteperdrix@xenomai.org>

Signed-off-by: Philippe Gerum <rpm@xenomai.org>
---
 kernel/drivers/net/stack/ipv4/icmp.c | 18 ++++++++++++++++--
 1 file changed, 16 insertions(+), 2 deletions(-)

diff --git a/kernel/drivers/net/stack/ipv4/icmp.c b/kernel/drivers/net/stack/ipv4/icmp.c
index 68489709c..556fee869 100644
--- a/kernel/drivers/net/stack/ipv4/icmp.c
+++ b/kernel/drivers/net/stack/ipv4/icmp.c
@@ -36,6 +36,7 @@
 #include <ipv4_chrdev.h>
 #include <ipv4/icmp.h>
 #include <ipv4/ip_fragment.h>
+#include <ipv4/ip_input.h>
 #include <ipv4/ip_output.h>
 #include <ipv4/protocol.h>
 #include <ipv4/route.h>
@@ -129,6 +130,14 @@ void rt_icmp_cleanup_echo_requests(void)
  */
 static void rt_icmp_discard(struct rtskb *skb)
 {
+#ifdef CONFIG_XENO_DRIVERS_NET_ADDON_PROXY
+    if (rt_ip_fallback_handler) {
+        /* If a fallback handler for IP protocol has been installed,
+         * call it. */
+	__rtskb_push(skb, skb->nh.iph->ihl*4 + sizeof(struct icmphdr));
+        rt_ip_fallback_handler(skb);
+    }
+#endif
 }
 
 static int rt_icmp_glue_reply_bits(const void *p, unsigned char *to,
@@ -207,6 +216,7 @@ static void rt_icmp_echo_reply(struct rtskb *skb)
 		rtdm_lock_put_irqrestore(&echo_calls_lock, context);
 	} else {
 		rtdm_lock_put_irqrestore(&echo_calls_lock, context);
+		rt_icmp_discard(skb);
 		return;
 	}
 
@@ -407,8 +417,12 @@ static struct rt_icmp_control rt_icmp_pointers[NR_ICMP_TYPES + 1] = {
  */
 struct rtsocket *rt_icmp_dest_socket(struct rtskb *skb)
 {
-	rt_socket_reference(icmp_socket);
-	return icmp_socket;
+	if (!list_empty(&echo_calls)) {
+	   rt_socket_reference(icmp_socket);
+	   return icmp_socket;
+	}
+
+	return NULL;
 }
 
 /***
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH 11/16] net/drivers: e1000e: enable multicast
  2019-03-21 17:13 [PATCH 00/16] multicast, VLAN support for RTnet Philippe Gerum
                   ` (9 preceding siblings ...)
  2019-03-21 17:13 ` [PATCH 10/16] net/ipv4: icmp: forward unused packets to proxy Philippe Gerum
@ 2019-03-21 17:13 ` Philippe Gerum
  2019-03-21 17:13 ` [PATCH 12/16] net/drivers: e1000e: enable VLAN filtering Philippe Gerum
                   ` (4 subsequent siblings)
  15 siblings, 0 replies; 19+ messages in thread
From: Philippe Gerum @ 2019-03-21 17:13 UTC (permalink / raw)
  To: xenomai; +Cc: Gilles Chanteperdrix, Philippe Gerum

From: Gilles Chanteperdrix <gilles.chanteperdrix@xenomai.org>

Signed-off-by: Philippe Gerum <rpm@xenomai.org>
---
 kernel/drivers/net/drivers/e1000e/e1000.h    | 2 +-
 kernel/drivers/net/drivers/e1000e/hw.h       | 2 +-
 kernel/drivers/net/drivers/e1000e/lib.c      | 7 ++++---
 kernel/drivers/net/drivers/e1000e/netdev.c   | 8 +++++---
 kernel/drivers/net/stack/include/ipv4/igmp.h | 4 ++--
 kernel/drivers/net/stack/ipv4/igmp.c         | 6 +++---
 6 files changed, 16 insertions(+), 13 deletions(-)

diff --git a/kernel/drivers/net/drivers/e1000e/e1000.h b/kernel/drivers/net/drivers/e1000e/e1000.h
index ee4e6fbe9..9abb446d8 100644
--- a/kernel/drivers/net/drivers/e1000e/e1000.h
+++ b/kernel/drivers/net/drivers/e1000e/e1000.h
@@ -575,7 +575,7 @@ extern s32 e1000e_setup_link(struct e1000_hw *hw);
 extern void e1000_clear_vfta_generic(struct e1000_hw *hw);
 extern void e1000e_init_rx_addrs(struct e1000_hw *hw, u16 rar_count);
 extern void e1000e_update_mc_addr_list_generic(struct e1000_hw *hw,
-					       u8 * mc_addr_list,
+					       struct rtdev_mc_list *mc_addr_list,
 					       u32 mc_addr_count);
 extern void e1000e_rar_set(struct e1000_hw *hw, u8 * addr, u32 index);
 extern s32 e1000e_set_fc_watermarks(struct e1000_hw *hw);
diff --git a/kernel/drivers/net/drivers/e1000e/hw.h b/kernel/drivers/net/drivers/e1000e/hw.h
index 8e2082423..875533fa0 100644
--- a/kernel/drivers/net/drivers/e1000e/hw.h
+++ b/kernel/drivers/net/drivers/e1000e/hw.h
@@ -779,7 +779,7 @@ struct e1000_mac_operations {
 	 s32(*get_link_up_info) (struct e1000_hw *, u16 *, u16 *);
 	 s32(*led_on) (struct e1000_hw *);
 	 s32(*led_off) (struct e1000_hw *);
-	void (*update_mc_addr_list) (struct e1000_hw *, u8 *, u32);
+	void (*update_mc_addr_list)(struct e1000_hw *, struct rtdev_mc_list *, u32);
 	 s32(*reset_hw) (struct e1000_hw *);
 	 s32(*init_hw) (struct e1000_hw *);
 	 s32(*setup_link) (struct e1000_hw *);
diff --git a/kernel/drivers/net/drivers/e1000e/lib.c b/kernel/drivers/net/drivers/e1000e/lib.c
index 327f838df..8165e602b 100644
--- a/kernel/drivers/net/drivers/e1000e/lib.c
+++ b/kernel/drivers/net/drivers/e1000e/lib.c
@@ -356,7 +356,8 @@ static u32 e1000_hash_mc_addr(struct e1000_hw *hw, u8 * mc_addr)
  *  The caller must have a packed mc_addr_list of multicast addresses.
  **/
 void e1000e_update_mc_addr_list_generic(struct e1000_hw *hw,
-					u8 * mc_addr_list, u32 mc_addr_count)
+					struct rtdev_mc_list *mc_addr_list,
+					u32 mc_addr_count)
 {
 	u32 hash_value, hash_bit, hash_reg;
 	int i;
@@ -366,13 +367,13 @@ void e1000e_update_mc_addr_list_generic(struct e1000_hw *hw,
 
 	/* update mta_shadow from mc_addr_list */
 	for (i = 0; (u32) i < mc_addr_count; i++) {
-		hash_value = e1000_hash_mc_addr(hw, mc_addr_list);
+		hash_value = e1000_hash_mc_addr(hw, mc_addr_list->dmi_addr);
 
 		hash_reg = (hash_value >> 5) & (hw->mac.mta_reg_count - 1);
 		hash_bit = hash_value & 0x1F;
 
 		hw->mac.mta_shadow[hash_reg] |= (1 << hash_bit);
-		mc_addr_list += (ETH_ALEN);
+		mc_addr_list = mc_addr_list->next;
 	}
 
 	/* replace the entire MTA table */
diff --git a/kernel/drivers/net/drivers/e1000e/netdev.c b/kernel/drivers/net/drivers/e1000e/netdev.c
index 4bd788700..7b49a795d 100644
--- a/kernel/drivers/net/drivers/e1000e/netdev.c
+++ b/kernel/drivers/net/drivers/e1000e/netdev.c
@@ -2152,8 +2152,9 @@ static void e1000_configure_rx(struct e1000_adapter *adapter)
  *  Updates the Multicast Table Array.
  *  The caller must have a packed mc_addr_list of multicast addresses.
  **/
-static void e1000_update_mc_addr_list(struct e1000_hw *hw, u8 * mc_addr_list,
-				      u32 mc_addr_count)
+static void e1000_update_mc_addr_list(struct e1000_hw *hw,
+				struct rtdev_mc_list *mc_addr_list,
+				u32 mc_addr_count)
 {
 	hw->mac.ops.update_mc_addr_list(hw, mc_addr_list, mc_addr_count);
 }
@@ -2194,7 +2195,7 @@ static void e1000_set_multi(struct rtnet_device *netdev)
 
 	ew32(RCTL, rctl);
 
-	e1000_update_mc_addr_list(hw, NULL, 0);
+	e1000_update_mc_addr_list(hw, netdev->mc_list, netdev->mc_count);
 
 	if (netdev->features & NETIF_F_HW_VLAN_CTAG_RX)
 		e1000e_vlan_strip_enable(adapter);
@@ -3986,6 +3987,7 @@ static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 	netdev->open = e1000_open;
 	netdev->stop = e1000_close;
 	netdev->hard_start_xmit = e1000_xmit_frame;
+	netdev->set_multicast_list = e1000_set_multi;
 	//netdev->get_stats = e1000_get_stats;
 	netdev->map_rtskb = e1000_map_rtskb;
 	netdev->unmap_rtskb = e1000_unmap_rtskb;
diff --git a/kernel/drivers/net/stack/include/ipv4/igmp.h b/kernel/drivers/net/stack/include/ipv4/igmp.h
index a44e09041..3daa343e4 100644
--- a/kernel/drivers/net/stack/include/ipv4/igmp.h
+++ b/kernel/drivers/net/stack/include/ipv4/igmp.h
@@ -87,8 +87,8 @@ static inline bool rtnet_in_multicast(u32 addr)
 }
 
 #ifdef CONFIG_XENO_DRIVERS_NET_RTIPV4_IGMP
-int rt_ip_mc_join_group(struct rtsocket *sk, struct ip_mreq *imr);
-int rt_ip_mc_leave_group(struct rtsocket *sk, struct ip_mreq *imr);
+int rt_ip_mc_join_group(struct rtsocket *sk, const struct ip_mreq *imr);
+int rt_ip_mc_leave_group(struct rtsocket *sk, const struct ip_mreq *imr);
 void rt_ip_mc_drop_socket(struct rtsocket *sk);
 void rt_ip_mc_dec_group(struct rtnet_device *rtdev, u32 addr);
 void rt_ip_mc_inc_group(struct rtnet_device *rtdev, u32 addr);
diff --git a/kernel/drivers/net/stack/ipv4/igmp.c b/kernel/drivers/net/stack/ipv4/igmp.c
index 3da21df5b..9568cedc7 100644
--- a/kernel/drivers/net/stack/ipv4/igmp.c
+++ b/kernel/drivers/net/stack/ipv4/igmp.c
@@ -339,7 +339,7 @@ void rt_ip_mc_dec_group(struct rtnet_device *rtdev, u32 addr)
     rtdm_lock_put_irqrestore(&mc_list_lock, flags);
 }
 
-static struct rtnet_device *rt_ip_mc_find_dev(struct ip_mreq *imr)
+static struct rtnet_device *rt_ip_mc_find_dev(const struct ip_mreq *imr)
 {
     struct rtnet_device *rtdev = NULL;
 
@@ -353,7 +353,7 @@ static struct rtnet_device *rt_ip_mc_find_dev(struct ip_mreq *imr)
  *	Join a socket to a group
  */
 
-int rt_ip_mc_join_group(struct rtsocket *sk, struct ip_mreq *imr)
+int rt_ip_mc_join_group(struct rtsocket *sk, const struct ip_mreq *imr)
 {
     int err = 0;
     u32 addr = imr->imr_multiaddr.s_addr;
@@ -399,7 +399,7 @@ int rt_ip_mc_join_group(struct rtsocket *sk, struct ip_mreq *imr)
 /*
  *	Ask a socket to leave a group.
  */
-int rt_ip_mc_leave_group(struct rtsocket *sk, struct ip_mreq *imr)
+int rt_ip_mc_leave_group(struct rtsocket *sk, const struct ip_mreq *imr)
 {
     u32 addr = imr->imr_multiaddr.s_addr;
     struct  rtnet_device *rtdev = rt_ip_mc_find_dev(imr);
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH 12/16] net/drivers: e1000e: enable VLAN filtering
  2019-03-21 17:13 [PATCH 00/16] multicast, VLAN support for RTnet Philippe Gerum
                   ` (10 preceding siblings ...)
  2019-03-21 17:13 ` [PATCH 11/16] net/drivers: e1000e: enable multicast Philippe Gerum
@ 2019-03-21 17:13 ` Philippe Gerum
  2019-03-21 17:13 ` [PATCH 13/16] net/drivers: e1000e: add netdevice stats Philippe Gerum
                   ` (3 subsequent siblings)
  15 siblings, 0 replies; 19+ messages in thread
From: Philippe Gerum @ 2019-03-21 17:13 UTC (permalink / raw)
  To: xenomai; +Cc: Gilles Chanteperdrix, Philippe Gerum

From: Gilles Chanteperdrix <gilles.chanteperdrix@xenomai.org>

Signed-off-by: Philippe Gerum <rpm@xenomai.org>
---
 kernel/drivers/net/drivers/e1000e/netdev.c | 30 +++++-----------------
 1 file changed, 6 insertions(+), 24 deletions(-)

diff --git a/kernel/drivers/net/drivers/e1000e/netdev.c b/kernel/drivers/net/drivers/e1000e/netdev.c
index 7b49a795d..0754a244f 100644
--- a/kernel/drivers/net/drivers/e1000e/netdev.c
+++ b/kernel/drivers/net/drivers/e1000e/netdev.c
@@ -1753,21 +1753,6 @@ static void e1000e_vlan_strip_disable(struct e1000_adapter *adapter)
 	ew32(CTRL, ctrl);
 }
 
-/**
- * e1000e_vlan_strip_enable - helper to enable HW VLAN stripping
- * @adapter: board private structure to initialize
- **/
-static void e1000e_vlan_strip_enable(struct e1000_adapter *adapter)
-{
-	struct e1000_hw *hw = &adapter->hw;
-	u32 ctrl;
-
-	/* enable VLAN tag insert/strip */
-	ctrl = er32(CTRL);
-	ctrl |= E1000_CTRL_VME;
-	ew32(CTRL, ctrl);
-}
-
 static void e1000_update_mng_vlan(struct e1000_adapter *adapter)
 {
 	struct rtnet_device *netdev = adapter->netdev;
@@ -2177,30 +2162,25 @@ static void e1000_set_multi(struct rtnet_device *netdev)
 	/* Check for Promiscuous and All Multicast modes */
 
 	rctl = er32(RCTL);
+	rctl &= ~(E1000_RCTL_UPE | E1000_RCTL_MPE);
 
 	if (netdev->flags & IFF_PROMISC) {
 		rctl |= (E1000_RCTL_UPE | E1000_RCTL_MPE);
-		rctl &= ~E1000_RCTL_VFE;
 		/* Do not hardware filter VLANs in promisc mode */
 		e1000e_vlan_filter_disable(adapter);
 	} else {
 		if (netdev->flags & IFF_ALLMULTI) {
 			rctl |= E1000_RCTL_MPE;
-			rctl &= ~E1000_RCTL_UPE;
 		} else {
-			rctl &= ~(E1000_RCTL_UPE | E1000_RCTL_MPE);
+			e1000_update_mc_addr_list(hw, netdev->mc_list, netdev->mc_count);
 		}
 		e1000e_vlan_filter_enable(adapter);
+		rctl |= E1000_RCTL_UPE;
 	}
 
 	ew32(RCTL, rctl);
 
-	e1000_update_mc_addr_list(hw, netdev->mc_list, netdev->mc_count);
-
-	if (netdev->features & NETIF_F_HW_VLAN_CTAG_RX)
-		e1000e_vlan_strip_enable(adapter);
-	else
-		e1000e_vlan_strip_disable(adapter);
+	e1000e_vlan_strip_disable(adapter);
 }
 
 /**
@@ -3995,6 +3975,8 @@ static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 
 	netdev->mem_start = mmio_start;
 	netdev->mem_end = mmio_start + mmio_len;
+	netdev->vlan_rx_add_vid = e1000_vlan_rx_add_vid;
+	netdev->vlan_rx_kill_vid = e1000_vlan_rx_kill_vid;
 
 	adapter->bd_number = cards_found++;
 
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH 13/16] net/drivers: e1000e: add netdevice stats
  2019-03-21 17:13 [PATCH 00/16] multicast, VLAN support for RTnet Philippe Gerum
                   ` (11 preceding siblings ...)
  2019-03-21 17:13 ` [PATCH 12/16] net/drivers: e1000e: enable VLAN filtering Philippe Gerum
@ 2019-03-21 17:13 ` Philippe Gerum
  2019-03-21 17:13 ` [PATCH 14/16] net/drivers: igb: enable multicast Philippe Gerum
                   ` (2 subsequent siblings)
  15 siblings, 0 replies; 19+ messages in thread
From: Philippe Gerum @ 2019-03-21 17:13 UTC (permalink / raw)
  To: xenomai; +Cc: Gilles Chanteperdrix, Philippe Gerum

From: Gilles Chanteperdrix <gilles.chanteperdrix@xenomai.org>

Signed-off-by: Philippe Gerum <rpm@xenomai.org>
---
 kernel/drivers/net/drivers/e1000e/e1000.h  |   4 +-
 kernel/drivers/net/drivers/e1000e/netdev.c | 234 ++++++++++++++++++++-
 2 files changed, 235 insertions(+), 3 deletions(-)

diff --git a/kernel/drivers/net/drivers/e1000e/e1000.h b/kernel/drivers/net/drivers/e1000e/e1000.h
index 9abb446d8..795a8da51 100644
--- a/kernel/drivers/net/drivers/e1000e/e1000.h
+++ b/kernel/drivers/net/drivers/e1000e/e1000.h
@@ -378,6 +378,7 @@ struct e1000_adapter {
 	struct e1000_hw_stats stats;
 	struct e1000_phy_info phy_info;
 	struct e1000_phy_stats phy_stats;
+	struct net_device_stats netdev_stats;
 
 	/* Snapshot of PHY registers */
 	struct e1000_phy_regs phy_regs;
@@ -505,8 +506,7 @@ extern int e1000e_setup_rx_resources(struct e1000_adapter *adapter);
 extern int e1000e_setup_tx_resources(struct e1000_adapter *adapter);
 extern void e1000e_free_rx_resources(struct e1000_adapter *adapter);
 extern void e1000e_free_tx_resources(struct e1000_adapter *adapter);
-extern struct rtnl_link_stats64 *e1000e_get_stats64(struct net_device *netdev, struct rtnl_link_stats64
-						    *stats);
+extern struct net_device_stats *e1000e_get_stats(struct rtnet_device *netdev);
 extern void e1000e_set_interrupt_capability(struct e1000_adapter *adapter);
 extern void e1000e_reset_interrupt_capability(struct e1000_adapter *adapter);
 extern void e1000e_get_hw_control(struct e1000_adapter *adapter);
diff --git a/kernel/drivers/net/drivers/e1000e/netdev.c b/kernel/drivers/net/drivers/e1000e/netdev.c
index 0754a244f..8516dbc89 100644
--- a/kernel/drivers/net/drivers/e1000e/netdev.c
+++ b/kernel/drivers/net/drivers/e1000e/netdev.c
@@ -2465,6 +2465,8 @@ static void e1000e_flush_descriptors(struct e1000_adapter *adapter)
 	e1e_flush();
 }
 
+static void e1000e_update_stats(struct e1000_adapter *adapter);
+
 void e1000e_down(struct e1000_adapter *adapter)
 {
 	struct rtnet_device *netdev = adapter->netdev;
@@ -2501,6 +2503,10 @@ void e1000e_down(struct e1000_adapter *adapter)
 
 	rtnetif_carrier_off(netdev);
 
+	spin_lock(&adapter->stats64_lock);
+	e1000e_update_stats(adapter);
+	spin_unlock(&adapter->stats64_lock);
+
 	e1000e_flush_descriptors(adapter);
 	e1000_clean_tx_ring(adapter);
 	e1000_clean_rx_ring(adapter);
@@ -2868,6 +2874,186 @@ static void e1000_update_phy_info(unsigned long data)
 	rtdm_schedule_nrt_work(&adapter->update_phy_task);
 }
 
+/**
+ * e1000e_update_phy_stats - Update the PHY statistics counters
+ * @adapter: board private structure
+ *
+ * Read/clear the upper 16-bit PHY registers and read/accumulate lower
+ **/
+static void e1000e_update_phy_stats(struct e1000_adapter *adapter)
+{
+	struct e1000_hw *hw = &adapter->hw;
+	s32 ret_val;
+	u16 phy_data;
+
+	ret_val = hw->phy.ops.acquire(hw);
+	if (ret_val)
+		return;
+
+	/* A page set is expensive so check if already on desired page.
+	 * If not, set to the page with the PHY status registers.
+	 */
+	hw->phy.addr = 1;
+	ret_val = e1000e_read_phy_reg_mdic(hw, IGP01E1000_PHY_PAGE_SELECT,
+					   &phy_data);
+	if (ret_val)
+		goto release;
+	if (phy_data != (HV_STATS_PAGE << IGP_PAGE_SHIFT)) {
+		ret_val = hw->phy.ops.set_page(hw,
+					       HV_STATS_PAGE << IGP_PAGE_SHIFT);
+		if (ret_val)
+			goto release;
+	}
+
+	/* Single Collision Count */
+	hw->phy.ops.read_reg_page(hw, HV_SCC_UPPER, &phy_data);
+	ret_val = hw->phy.ops.read_reg_page(hw, HV_SCC_LOWER, &phy_data);
+	if (!ret_val)
+		adapter->stats.scc += phy_data;
+
+	/* Excessive Collision Count */
+	hw->phy.ops.read_reg_page(hw, HV_ECOL_UPPER, &phy_data);
+	ret_val = hw->phy.ops.read_reg_page(hw, HV_ECOL_LOWER, &phy_data);
+	if (!ret_val)
+		adapter->stats.ecol += phy_data;
+
+	/* Multiple Collision Count */
+	hw->phy.ops.read_reg_page(hw, HV_MCC_UPPER, &phy_data);
+	ret_val = hw->phy.ops.read_reg_page(hw, HV_MCC_LOWER, &phy_data);
+	if (!ret_val)
+		adapter->stats.mcc += phy_data;
+
+	/* Late Collision Count */
+	hw->phy.ops.read_reg_page(hw, HV_LATECOL_UPPER, &phy_data);
+	ret_val = hw->phy.ops.read_reg_page(hw, HV_LATECOL_LOWER, &phy_data);
+	if (!ret_val)
+		adapter->stats.latecol += phy_data;
+
+	/* Collision Count - also used for adaptive IFS */
+	hw->phy.ops.read_reg_page(hw, HV_COLC_UPPER, &phy_data);
+	ret_val = hw->phy.ops.read_reg_page(hw, HV_COLC_LOWER, &phy_data);
+	if (!ret_val)
+		hw->mac.collision_delta = phy_data;
+
+	/* Defer Count */
+	hw->phy.ops.read_reg_page(hw, HV_DC_UPPER, &phy_data);
+	ret_val = hw->phy.ops.read_reg_page(hw, HV_DC_LOWER, &phy_data);
+	if (!ret_val)
+		adapter->stats.dc += phy_data;
+
+	/* Transmit with no CRS */
+	hw->phy.ops.read_reg_page(hw, HV_TNCRS_UPPER, &phy_data);
+	ret_val = hw->phy.ops.read_reg_page(hw, HV_TNCRS_LOWER, &phy_data);
+	if (!ret_val)
+		adapter->stats.tncrs += phy_data;
+
+release:
+	hw->phy.ops.release(hw);
+}
+
+/**
+ * e1000e_update_stats - Update the board statistics counters
+ * @adapter: board private structure
+ **/
+static void e1000e_update_stats(struct e1000_adapter *adapter)
+{
+	struct e1000_hw *hw = &adapter->hw;
+	struct pci_dev *pdev = adapter->pdev;
+
+	/* Prevent stats update while adapter is being reset, or if the pci
+	 * connection is down.
+	 */
+	if (adapter->link_speed == 0)
+	return;
+	if (pci_channel_offline(pdev))
+		return;
+
+	adapter->stats.crcerrs += er32(CRCERRS);
+	adapter->stats.gprc += er32(GPRC);
+	adapter->stats.gorc += er32(GORCL);
+	er32(GORCH);		/* Clear gorc */
+	adapter->stats.bprc += er32(BPRC);
+	adapter->stats.mprc += er32(MPRC);
+	adapter->stats.roc += er32(ROC);
+
+	adapter->stats.mpc += er32(MPC);
+
+	/* Half-duplex statistics */
+	if (adapter->link_duplex == HALF_DUPLEX) {
+		if (adapter->flags2 & FLAG2_HAS_PHY_STATS) {
+			e1000e_update_phy_stats(adapter);
+		} else {
+			adapter->stats.scc += er32(SCC);
+			adapter->stats.ecol += er32(ECOL);
+			adapter->stats.mcc += er32(MCC);
+			adapter->stats.latecol += er32(LATECOL);
+			adapter->stats.dc += er32(DC);
+
+			hw->mac.collision_delta = er32(COLC);
+
+			if ((hw->mac.type != e1000_82574) &&
+			    (hw->mac.type != e1000_82583))
+				adapter->stats.tncrs += er32(TNCRS);
+		}
+		adapter->stats.colc += hw->mac.collision_delta;
+	}
+
+	adapter->stats.xonrxc += er32(XONRXC);
+	adapter->stats.xontxc += er32(XONTXC);
+	adapter->stats.xoffrxc += er32(XOFFRXC);
+	adapter->stats.xofftxc += er32(XOFFTXC);
+	adapter->stats.gptc += er32(GPTC);
+	adapter->stats.gotc += er32(GOTCL);
+	er32(GOTCH);		/* Clear gotc */
+	adapter->stats.rnbc += er32(RNBC);
+	adapter->stats.ruc += er32(RUC);
+
+	adapter->stats.mptc += er32(MPTC);
+	adapter->stats.bptc += er32(BPTC);
+
+	/* used for adaptive IFS */
+
+	hw->mac.tx_packet_delta = er32(TPT);
+	adapter->stats.tpt += hw->mac.tx_packet_delta;
+
+	adapter->stats.algnerrc += er32(ALGNERRC);
+	adapter->stats.rxerrc += er32(RXERRC);
+	adapter->stats.cexterr += er32(CEXTERR);
+	adapter->stats.tsctc += er32(TSCTC);
+	adapter->stats.tsctfc += er32(TSCTFC);
+
+	/* Fill out the OS statistics structure */
+	adapter->netdev_stats.multicast = adapter->stats.mprc;
+	adapter->netdev_stats.collisions = adapter->stats.colc;
+
+	/* Rx Errors */
+
+	/* RLEC on some newer hardware can be incorrect so build
+	 * our own version based on RUC and ROC
+	 */
+	adapter->netdev_stats.rx_errors = adapter->stats.rxerrc +
+	    adapter->stats.crcerrs + adapter->stats.algnerrc +
+	    adapter->stats.ruc + adapter->stats.roc + adapter->stats.cexterr;
+	adapter->netdev_stats.rx_length_errors = adapter->stats.ruc +
+	    adapter->stats.roc;
+	adapter->netdev_stats.rx_crc_errors = adapter->stats.crcerrs;
+	adapter->netdev_stats.rx_frame_errors = adapter->stats.algnerrc;
+	adapter->netdev_stats.rx_missed_errors = adapter->stats.mpc;
+
+	/* Tx Errors */
+	adapter->netdev_stats.tx_errors = adapter->stats.ecol + adapter->stats.latecol;
+	adapter->netdev_stats.tx_aborted_errors = adapter->stats.ecol;
+	adapter->netdev_stats.tx_window_errors = adapter->stats.latecol;
+	adapter->netdev_stats.tx_carrier_errors = adapter->stats.tncrs;
+
+	/* Tx Dropped needs to be maintained elsewhere */
+
+	/* Management Stats */
+	adapter->stats.mgptc += er32(MGTPTC);
+	adapter->stats.mgprc += er32(MGTPRC);
+	adapter->stats.mgpdc += er32(MGTPDC);
+}
+
 /**
  * e1000_phy_read_status - Update the PHY register status snapshot
  * @adapter: board private structure
@@ -3159,6 +3345,7 @@ static void e1000_watchdog_task(struct work_struct *work)
 
 link_up:
 	spin_lock(&adapter->stats64_lock);
+	e1000e_update_stats(adapter);
 
 	mac->tx_packet_delta = adapter->stats.tpt - adapter->tpt_old;
 	adapter->tpt_old = adapter->stats.tpt;
@@ -3424,6 +3611,51 @@ static void e1000_reset_task(struct work_struct *work)
 	e1000e_reinit_locked(adapter);
 }
 
+struct net_device_stats *e1000_get_stats(struct rtnet_device *netdev)
+{
+	struct e1000_adapter *adapter = rtnetdev_priv(netdev);
+	struct net_device_stats *stats = &adapter->netdev_stats;
+
+	memset(stats, 0, sizeof(*stats));
+	spin_lock(&adapter->stats64_lock);
+	e1000e_update_stats(adapter);
+	/* Fill out the OS statistics structure */
+	stats->rx_bytes = adapter->stats.gorc;
+	stats->rx_packets = adapter->stats.gprc;
+	stats->tx_bytes = adapter->stats.gotc;
+	stats->tx_packets = adapter->stats.gptc;
+	stats->multicast = adapter->stats.mprc;
+	stats->collisions = adapter->stats.colc;
+
+	/* Rx Errors */
+
+	/*
+	 * RLEC on some newer hardware can be incorrect so build
+	 * our own version based on RUC and ROC
+	 */
+	stats->rx_errors = adapter->stats.rxerrc +
+		adapter->stats.crcerrs + adapter->stats.algnerrc +
+		adapter->stats.ruc + adapter->stats.roc +
+		adapter->stats.cexterr;
+	stats->rx_length_errors = adapter->stats.ruc +
+					      adapter->stats.roc;
+	stats->rx_crc_errors = adapter->stats.crcerrs;
+	stats->rx_frame_errors = adapter->stats.algnerrc;
+	stats->rx_missed_errors = adapter->stats.mpc;
+
+	/* Tx Errors */
+	stats->tx_errors = adapter->stats.ecol +
+				       adapter->stats.latecol;
+	stats->tx_aborted_errors = adapter->stats.ecol;
+	stats->tx_window_errors = adapter->stats.latecol;
+	stats->tx_carrier_errors = adapter->stats.tncrs;
+
+	/* Tx Dropped needs to be maintained elsewhere */
+
+	spin_unlock(&adapter->stats64_lock);
+	return stats;
+}
+
 static int e1000_init_phy_wakeup(struct e1000_adapter *adapter, u32 wufc)
 {
 	struct e1000_hw *hw = &adapter->hw;
@@ -3968,7 +4200,7 @@ static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 	netdev->stop = e1000_close;
 	netdev->hard_start_xmit = e1000_xmit_frame;
 	netdev->set_multicast_list = e1000_set_multi;
-	//netdev->get_stats = e1000_get_stats;
+	netdev->get_stats = e1000_get_stats;
 	netdev->map_rtskb = e1000_map_rtskb;
 	netdev->unmap_rtskb = e1000_unmap_rtskb;
 	strncpy(netdev->name, pci_name(pdev), sizeof(netdev->name) - 1);
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH 14/16] net/drivers: igb: enable multicast
  2019-03-21 17:13 [PATCH 00/16] multicast, VLAN support for RTnet Philippe Gerum
                   ` (12 preceding siblings ...)
  2019-03-21 17:13 ` [PATCH 13/16] net/drivers: e1000e: add netdevice stats Philippe Gerum
@ 2019-03-21 17:13 ` Philippe Gerum
  2019-03-21 17:13 ` [PATCH 15/16] net/drivers: igb: enable VLAN filtering Philippe Gerum
  2019-03-21 17:13 ` [PATCH 16/16] demo/net: add rtnet tests Philippe Gerum
  15 siblings, 0 replies; 19+ messages in thread
From: Philippe Gerum @ 2019-03-21 17:13 UTC (permalink / raw)
  To: xenomai; +Cc: Gilles Chanteperdrix, Philippe Gerum

From: Gilles Chanteperdrix <gilles.chanteperdrix@xenomai.org>

Signed-off-by: Philippe Gerum <rpm@xenomai.org>
---
 kernel/drivers/net/drivers/igb/e1000_mac.c |  6 ++---
 kernel/drivers/net/drivers/igb/e1000_mac.h |  2 +-
 kernel/drivers/net/drivers/igb/igb_main.c  | 30 +++++-----------------
 3 files changed, 11 insertions(+), 27 deletions(-)

diff --git a/kernel/drivers/net/drivers/igb/e1000_mac.c b/kernel/drivers/net/drivers/igb/e1000_mac.c
index 5b7a82d25..77db892ac 100644
--- a/kernel/drivers/net/drivers/igb/e1000_mac.c
+++ b/kernel/drivers/net/drivers/igb/e1000_mac.c
@@ -438,7 +438,7 @@ static u32 igb_hash_mc_addr(struct e1000_hw *hw, u8 * mc_addr)
  *  The caller must have a packed mc_addr_list of multicast addresses.
  **/
 void igb_update_mc_addr_list(struct e1000_hw *hw,
-			     u8 * mc_addr_list, u32 mc_addr_count)
+			     struct rtdev_mc_list *mc_addr, u32 mc_addr_count)
 {
 	u32 hash_value, hash_bit, hash_reg;
 	int i;
@@ -448,13 +448,13 @@ void igb_update_mc_addr_list(struct e1000_hw *hw,
 
 	/* update mta_shadow from mc_addr_list */
 	for (i = 0; (u32) i < mc_addr_count; i++) {
-		hash_value = igb_hash_mc_addr(hw, mc_addr_list);
+		hash_value = igb_hash_mc_addr(hw, mc_addr->dmi_addr);
 
 		hash_reg = (hash_value >> 5) & (hw->mac.mta_reg_count - 1);
 		hash_bit = hash_value & 0x1F;
 
 		hw->mac.mta_shadow[hash_reg] |= (1 << hash_bit);
-		mc_addr_list += (ETH_ALEN);
+		mc_addr = mc_addr->next;
 	}
 
 	/* replace the entire MTA table */
diff --git a/kernel/drivers/net/drivers/igb/e1000_mac.h b/kernel/drivers/net/drivers/igb/e1000_mac.h
index 7f3744cf5..af1b6457f 100644
--- a/kernel/drivers/net/drivers/igb/e1000_mac.h
+++ b/kernel/drivers/net/drivers/igb/e1000_mac.h
@@ -49,7 +49,7 @@ s32 igb_get_speed_and_duplex_copper(struct e1000_hw *hw, u16 * speed,
 s32 igb_id_led_init(struct e1000_hw *hw);
 s32 igb_led_off(struct e1000_hw *hw);
 void igb_update_mc_addr_list(struct e1000_hw *hw,
-			     u8 * mc_addr_list, u32 mc_addr_count);
+			struct rtdev_mc_list *mc_addr, u32 mc_addr_count);
 s32 igb_setup_link(struct e1000_hw *hw);
 s32 igb_validate_mdi_setting(struct e1000_hw *hw);
 s32 igb_write_8bit_ctrl_reg(struct e1000_hw *hw, u32 reg, u32 offset, u8 data);
diff --git a/kernel/drivers/net/drivers/igb/igb_main.c b/kernel/drivers/net/drivers/igb/igb_main.c
index 06c9d7818..2b3957eae 100644
--- a/kernel/drivers/net/drivers/igb/igb_main.c
+++ b/kernel/drivers/net/drivers/igb/igb_main.c
@@ -2047,8 +2047,8 @@ static int igb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 	netdev->map_rtskb = igb_map_rtskb;
 	netdev->unmap_rtskb = igb_unmap_rtskb;
 	netdev->do_ioctl = igb_ioctl;
+	netdev->set_multicast_list = igb_set_rx_mode;
 #if 0
-	netdev->set_multicast_list = igb_set_multi;
 	netdev->set_mac_address = igb_set_mac;
 	netdev->change_mtu = igb_change_mtu;
 
@@ -3333,34 +3333,18 @@ static int igb_write_mc_addr_list(struct rtnet_device *netdev)
 {
 	struct igb_adapter *adapter = rtnetdev_priv(netdev);
 	struct e1000_hw *hw = &adapter->hw;
-#if 0
-	struct netdev_hw_addr *ha;
-	u8 *mta_list;
-	int i;
-	if (netdev_mc_empty(netdev)) {
+	struct rtdev_mc_list *mc_addr = netdev->mc_list;
+	unsigned mc_addr_count = netdev->mc_count;
+
+	if (!mc_addr_count) {
 		/* nothing to program, so clear mc list */
 		igb_update_mc_addr_list(hw, NULL, 0);
-		igb_restore_vf_multicasts(adapter);
 		return 0;
 	}
 
-	mta_list = kzalloc(netdev_mc_count(netdev) * 6, GFP_ATOMIC);
-	if (!mta_list)
-		return -ENOMEM;
-
-	/* The shared function expects a packed array of only addresses. */
-	i = 0;
-	netdev_for_each_mc_addr(ha, netdev)
-	    memcpy(mta_list + (i++ * ETH_ALEN), ha->addr, ETH_ALEN);
-
-	igb_update_mc_addr_list(hw, mta_list, i);
-	kfree(mta_list);
+	igb_update_mc_addr_list(hw, mc_addr, mc_addr_count);
 
-	return netdev_mc_count(netdev);
-#else
-	igb_update_mc_addr_list(hw, NULL, 0);
-	return 0;
-#endif
+	return mc_addr_count;
 }
 
 /**
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH 15/16] net/drivers: igb: enable VLAN filtering
  2019-03-21 17:13 [PATCH 00/16] multicast, VLAN support for RTnet Philippe Gerum
                   ` (13 preceding siblings ...)
  2019-03-21 17:13 ` [PATCH 14/16] net/drivers: igb: enable multicast Philippe Gerum
@ 2019-03-21 17:13 ` Philippe Gerum
  2019-03-21 17:13 ` [PATCH 16/16] demo/net: add rtnet tests Philippe Gerum
  15 siblings, 0 replies; 19+ messages in thread
From: Philippe Gerum @ 2019-03-21 17:13 UTC (permalink / raw)
  To: xenomai; +Cc: Gilles Chanteperdrix, Philippe Gerum

From: Gilles Chanteperdrix <gilles.chanteperdrix@xenomai.org>

Signed-off-by: Philippe Gerum <rpm@xenomai.org>
---
 kernel/drivers/net/drivers/igb/igb_main.c | 23 ++++++++++++++++-------
 1 file changed, 16 insertions(+), 7 deletions(-)

diff --git a/kernel/drivers/net/drivers/igb/igb_main.c b/kernel/drivers/net/drivers/igb/igb_main.c
index 2b3957eae..399056043 100644
--- a/kernel/drivers/net/drivers/igb/igb_main.c
+++ b/kernel/drivers/net/drivers/igb/igb_main.c
@@ -221,7 +221,8 @@ static int igb_ioctl(struct rtnet_device *, struct ifreq *ifr, int cmd);
 static void igb_reset_task(struct work_struct *);
 static void igb_vlan_mode(struct rtnet_device *netdev,
 			  netdev_features_t features);
-static int igb_vlan_rx_add_vid(struct rtnet_device *, __be16, u16);
+static void igb_vlan_rx_add_vid(struct rtnet_device *, u16);
+static void igb_vlan_rx_kill_vid(struct rtnet_device *, u16);
 static void igb_restore_vlan(struct igb_adapter *);
 static void igb_rar_set_qsel(struct igb_adapter *, u8 *, u32, u8);
 
@@ -2048,6 +2049,8 @@ static int igb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 	netdev->unmap_rtskb = igb_unmap_rtskb;
 	netdev->do_ioctl = igb_ioctl;
 	netdev->set_multicast_list = igb_set_rx_mode;
+	netdev->vlan_rx_add_vid = igb_vlan_rx_add_vid;
+	netdev->vlan_rx_kill_vid = igb_vlan_rx_kill_vid;
 #if 0
 	netdev->set_mac_address = igb_set_mac;
 	netdev->change_mtu = igb_change_mtu;
@@ -2110,10 +2113,8 @@ static int igb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 	    NETIF_F_RXHASH |
 	    NETIF_F_RXCSUM | NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_HW_VLAN_CTAG_TX;
 
-#if 0
 	/* set this bit last since it cannot be part of hw_features */
 	netdev->features |= NETIF_F_HW_VLAN_CTAG_FILTER;
-#endif
 
 	netdev->priv_flags |= IFF_SUPP_NOFCS;
 
@@ -5076,8 +5077,7 @@ static void igb_vlan_mode(struct rtnet_device *netdev,
 	igb_rlpml_set(adapter);
 }
 
-static int igb_vlan_rx_add_vid(struct rtnet_device *netdev,
-			       __be16 proto, u16 vid)
+static void igb_vlan_rx_add_vid(struct rtnet_device *netdev, u16 vid)
 {
 	struct igb_adapter *adapter = rtnetdev_priv(netdev);
 	struct e1000_hw *hw = &adapter->hw;
@@ -5086,8 +5086,17 @@ static int igb_vlan_rx_add_vid(struct rtnet_device *netdev,
 	igb_vfta_set(hw, vid, true);
 
 	set_bit(vid, adapter->active_vlans);
+}
 
-	return 0;
+static void igb_vlan_rx_kill_vid(struct rtnet_device *netdev, u16 vid)
+{
+	struct igb_adapter *adapter = rtnetdev_priv(netdev);
+	struct e1000_hw *hw = &adapter->hw;
+
+	/* if vid was not present in VLVF just remove it from table */
+	igb_vfta_set(hw, vid, false);
+
+	clear_bit(vid, adapter->active_vlans);
 }
 
 static void igb_restore_vlan(struct igb_adapter *adapter)
@@ -5097,7 +5106,7 @@ static void igb_restore_vlan(struct igb_adapter *adapter)
 	igb_vlan_mode(adapter->netdev, adapter->netdev->features);
 
 	for_each_set_bit(vid, adapter->active_vlans, VLAN_N_VID)
-	    igb_vlan_rx_add_vid(adapter->netdev, htons(ETH_P_8021Q), vid);
+	    igb_vlan_rx_add_vid(adapter->netdev, vid);
 }
 
 static int __igb_shutdown(struct pci_dev *pdev, bool * enable_wake,
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH 16/16] demo/net: add rtnet tests
  2019-03-21 17:13 [PATCH 00/16] multicast, VLAN support for RTnet Philippe Gerum
                   ` (14 preceding siblings ...)
  2019-03-21 17:13 ` [PATCH 15/16] net/drivers: igb: enable VLAN filtering Philippe Gerum
@ 2019-03-21 17:13 ` Philippe Gerum
  2019-03-21 23:31   ` Still More Slackspot Issues - Patch Included Stephen D. Cohen
  15 siblings, 1 reply; 19+ messages in thread
From: Philippe Gerum @ 2019-03-21 17:13 UTC (permalink / raw)
  To: xenomai; +Cc: Gilles Chanteperdrix, Philippe Gerum

From: Gilles Chanteperdrix <gilles.chanteperdrix@xenomai.org>

Signed-off-by: Philippe Gerum <rpm@xenomai.org>
---
 configure.ac                   |   1 +
 demo/Makefile.am               |   2 +-
 demo/net/Makefile.am           |  78 ++++++++
 demo/net/mcast-receiver.c      | 204 ++++++++++++++++++++
 demo/net/mcast-sender.c        | 151 +++++++++++++++
 demo/net/raw-ethernet.c        | 100 ++++++++++
 demo/net/rtt-mcast-measure.c   | 210 ++++++++++++++++++++
 demo/net/rtt-mcast-responder.c | 109 +++++++++++
 demo/net/rtt-responder.c       | 193 +++++++++++++++++++
 demo/net/rtt-sender.c          | 341 +++++++++++++++++++++++++++++++++
 demo/net/rttcp-client.c        | 212 ++++++++++++++++++++
 demo/net/rttcp-server.c        | 181 +++++++++++++++++
 demo/net/udp-send.c            | 136 +++++++++++++
 13 files changed, 1917 insertions(+), 1 deletion(-)
 create mode 100644 demo/net/Makefile.am
 create mode 100644 demo/net/mcast-receiver.c
 create mode 100644 demo/net/mcast-sender.c
 create mode 100644 demo/net/raw-ethernet.c
 create mode 100644 demo/net/rtt-mcast-measure.c
 create mode 100644 demo/net/rtt-mcast-responder.c
 create mode 100644 demo/net/rtt-responder.c
 create mode 100644 demo/net/rtt-sender.c
 create mode 100644 demo/net/rttcp-client.c
 create mode 100644 demo/net/rttcp-server.c
 create mode 100644 demo/net/udp-send.c

diff --git a/configure.ac b/configure.ac
index b8fd2fbed..546cfde4c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -990,6 +990,7 @@ AC_CONFIG_FILES([ \
 	demo/posix/cobalt/Makefile \
 	demo/alchemy/Makefile \
 	demo/alchemy/cobalt/Makefile \
+	demo/net/Makefile \
 	include/Makefile \
 	include/cobalt/uapi/Makefile \
 	include/cobalt/uapi/asm-generic/Makefile \
diff --git a/demo/Makefile.am b/demo/Makefile.am
index fe5107c25..2839d074b 100644
--- a/demo/Makefile.am
+++ b/demo/Makefile.am
@@ -1,2 +1,2 @@
 
-SUBDIRS = posix alchemy
+SUBDIRS = posix alchemy net
diff --git a/demo/net/Makefile.am b/demo/net/Makefile.am
new file mode 100644
index 000000000..f9755bace
--- /dev/null
+++ b/demo/net/Makefile.am
@@ -0,0 +1,78 @@
+demodir = @XENO_DEMO_DIR@
+
+CCLD = $(top_srcdir)/scripts/wrap-link.sh $(CC)
+
+demo_PROGRAMS = 	\
+	mcast-receiver	\
+	mcast-sender	\
+	raw-ethernet	\
+	rttcp-client	\
+	rttcp-server	\
+	rtt-mcast-measure	\
+	rtt-mcast-responder	\
+	rtt-responder	\
+	rtt-sender	\
+	udp-send
+
+cppflags = 			\
+	$(XENO_USER_CFLAGS)	\
+	-I$(top_srcdir)/include
+
+ldflags = @XENO_AUTOINIT_LDFLAGS@ $(XENO_POSIX_WRAPPERS)
+
+ldadd = 					\
+	 @XENO_CORE_LDADD@			\
+	 @XENO_USER_LDADD@			\
+	-lpthread -lrt
+
+mcast_receiver_SOURCES = mcast-receiver.c
+mcast_receiver_CPPFLAGS = $(cppflags)
+mcast_receiver_LDFLAGS = $(ldflags)
+mcast_receiver_LDADD = $(ldadd)
+
+mcast_sender_SOURCES = mcast-sender.c
+mcast_sender_CPPFLAGS = $(cppflags)
+mcast_sender_LDFLAGS = $(ldflags)
+mcast_sender_LDADD = $(ldadd)
+
+raw_ethernet_SOURCES = raw-ethernet.c
+raw_ethernet_CPPFLAGS = $(cppflags)
+raw_ethernet_LDFLAGS = $(ldflags)
+raw_ethernet_LDADD = $(ldadd)
+
+rttcp_client_SOURCES = rttcp-client.c
+rttcp_client_CPPFLAGS = $(cppflags)
+rttcp_client_LDFLAGS = $(ldflags)
+rttcp_client_LDADD = $(ldadd)
+
+rttcp_server_SOURCES = rttcp-server.c
+rttcp_server_CPPFLAGS = $(cppflags)
+rttcp_server_LDFLAGS = $(ldflags)
+rttcp_server_LDADD = $(ldadd)
+
+rtt_mcast_measure_SOURCES = rtt-mcast-measure.c
+rtt_mcast_measure_CPPFLAGS = $(cppflags)
+rtt_mcast_measure_LDFLAGS = $(ldflags)
+rtt_mcast_measure_LDADD = ../../lib/alchemy/libalchemy.la 	\
+		../../lib/copperplate/libcopperplate.la		\
+		$(ldadd)
+
+rtt_mcast_responder_SOURCES = rtt-mcast-responder.c
+rtt_mcast_responder_CPPFLAGS = $(cppflags)
+rtt_mcast_responder_LDFLAGS = $(ldflags)
+rtt_mcast_responder_LDADD = $(ldadd)
+
+rtt_responder_SOURCES = rtt-responder.c
+rtt_responder_CPPFLAGS = $(cppflags)
+rtt_responder_LDFLAGS = $(ldflags)
+rtt_responder_LDADD = $(ldadd)
+
+rtt_sender_SOURCES = rtt-sender.c
+rtt_sender_CPPFLAGS = $(cppflags)
+rtt_sender_LDFLAGS = $(ldflags)
+rtt_sender_LDADD = $(ldadd)
+
+udp_send_SOURCES = udp-send.c
+udp_send_CPPFLAGS = $(cppflags)
+udp_send_LDFLAGS = $(ldflags)
+udp_send_LDADD = $(ldadd)
diff --git a/demo/net/mcast-receiver.c b/demo/net/mcast-receiver.c
new file mode 100644
index 000000000..253e168df
--- /dev/null
+++ b/demo/net/mcast-receiver.c
@@ -0,0 +1,204 @@
+/*
+ * listener.c -- joins a multicast group and echoes all data it receives from
+ *		the group to its stdout...
+ *
+ * Antony Courtney,	25/11/94
+ * Modified by: Frédéric Bastien (25/03/04)
+ * to compile without warning and work correctly
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <time.h>
+#include <string.h>
+#include <sched.h>
+#include <pthread.h>
+#include <errno.h>
+
+#include <sys/ioctl.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <signal.h>
+
+#include <execinfo.h>
+
+#define HELLO_PORT 12345
+#define HELLO_GROUP "225.0.0.37"
+#define MSGBUFSIZE 256
+
+#define TO_US(ns) \
+    (ns) / 1000, (ns) % 1000
+
+static void check(const char *file, int line, const char *service, int status, int err)
+{
+	if (status >= 0)
+		return;
+
+	pthread_setmode_np(PTHREAD_WARNSW, 0, NULL);
+	__real_fprintf(stderr, "%s:%d: %s: %s\n", file, line, service, strerror(err));
+
+	exit(EXIT_FAILURE);
+}
+
+#define check_pthread(expr)						\
+    ({									\
+	    int _status = (expr);					\
+	    check(__FILE__, __LINE__, #expr, -_status, _status);	\
+    })
+
+#define check_unix(expr)					\
+    ({								\
+	    int _status = (expr);				\
+	    check(__FILE__, __LINE__, #expr, _status, errno);	\
+    })
+
+static const char *reason_str[] = {
+	[SIGDEBUG_UNDEFINED] = "received SIGDEBUG for unknown reason",
+	[SIGDEBUG_MIGRATE_SIGNAL] = "received signal",
+	[SIGDEBUG_MIGRATE_SYSCALL] = "invoked syscall",
+	[SIGDEBUG_MIGRATE_FAULT] = "triggered fault",
+	[SIGDEBUG_MIGRATE_PRIOINV] = "owner is not in real-time mode",
+	[SIGDEBUG_NOMLOCK] = "process memory not locked",
+	[SIGDEBUG_WATCHDOG] = "watchdog triggered (period too short?)",
+	[SIGDEBUG_LOCK_BREAK] = "scheduler lock break",
+	[SIGDEBUG_MUTEX_SLEEP] = "caller sleeps with mutex",
+};
+
+static void sigdebug(int sig, siginfo_t *si, void *context)
+{
+	const char fmt[] = "%s, aborting.\n";
+	unsigned int reason = sigdebug_reason(si);
+	int n __attribute__ ((unused));
+	static char buffer[256];
+	void *bt[32];
+	int nentries;
+
+	if (reason >= sizeof(reason_str) / sizeof(reason_str[0]))
+		reason = SIGDEBUG_UNDEFINED;
+
+	n = snprintf(buffer, sizeof(buffer), fmt, reason_str[reason]);
+	n = write(STDERR_FILENO, buffer, n);
+	nentries = backtrace(bt, sizeof(bt) / sizeof(bt[0]));
+	backtrace_symbols_fd(bt, nentries, STDERR_FILENO);
+
+	signal(sig, SIG_DFL);
+	kill(getpid(), sig);
+}
+
+int main(int argc, char *argv[])
+{
+	unsigned long long min, max, sum, count, gmin, gmax, gsum, gcount;
+	struct sigaction sa __attribute__((unused));
+	struct sockaddr_in addr;
+	int fd, err;
+	struct ip_mreq mreq;
+	socklen_t addrlen;
+	struct timespec last_print;
+	struct sched_param sparm;
+	char msgbuf[MSGBUFSIZE];
+	bool first = true;
+
+	if (argc != 2) {
+		fprintf(stderr, "Local ip address expected as first and "
+			"only argument\n");
+		exit(EXIT_FAILURE);
+	}
+
+	sparm.sched_priority = 97;
+	check_pthread(pthread_setschedparam(pthread_self(),
+						    SCHED_FIFO, &sparm));
+
+	check_unix(fd = socket(AF_INET,SOCK_DGRAM,0));
+
+	sigemptyset(&sa.sa_mask);
+	sa.sa_sigaction = sigdebug;
+	sa.sa_flags = SA_SIGINFO;
+	check_unix(sigaction(SIGDEBUG, &sa, NULL));
+
+	memset(&addr,0,sizeof(addr));
+	addr.sin_family = AF_INET;
+	addr.sin_addr.s_addr = inet_addr(argv[1]);
+	addr.sin_port = htons(HELLO_PORT);
+
+	check_unix(bind(fd, (struct sockaddr *)&addr,sizeof(addr)));
+
+	mreq.imr_multiaddr.s_addr = inet_addr(HELLO_GROUP);
+	mreq.imr_interface.s_addr = addr.sin_addr.s_addr;
+	check_unix(setsockopt(fd,IPPROTO_IP,
+				IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)));
+
+	gmin = min = ~0ULL;
+	gmax = max = 0;
+	gsum = sum = 0;
+	gcount = count = 0;
+
+	check_pthread(pthread_setmode_np(0, PTHREAD_WARNSW, NULL));
+
+	check_unix(clock_gettime(CLOCK_REALTIME, &last_print));
+
+	while (1) {
+		struct timespec now;
+		struct timeval packet;
+		unsigned long long diff;
+
+		addrlen = sizeof(addr);
+		check_unix(recvfrom(fd, msgbuf, sizeof(msgbuf), 0,
+					(struct sockaddr *)&addr, &addrlen));
+		check_unix(clock_gettime(CLOCK_REALTIME, &now));
+
+		err = ioctl(fd, SIOCGSTAMP, &packet);
+		if (err < 0) {
+			perror("ioctl");
+			exit(1);
+		}
+
+		if (first) {
+			first = false;
+			continue;
+		}
+
+		diff = now.tv_sec * 1000000000ULL + now.tv_nsec -
+			(packet.tv_sec * 1000000000ULL
+			+ packet.tv_usec * 1000ULL);
+		if ((long long)diff < 0)
+			printf("%lu.%09lu - %lu.%06lu\n",
+				now.tv_sec, now.tv_nsec,
+				packet.tv_sec, packet.tv_usec);
+
+		if (diff < min)
+			min = diff;
+		if (diff > max)
+			max = diff;
+		sum += diff;
+		++count;
+
+		diff = now.tv_sec * 1000000000ULL + now.tv_nsec -
+			(last_print.tv_sec * 1000000000ULL
+			+ last_print.tv_nsec);
+		if (diff < 1000000000)
+			continue;
+
+		if (min < gmin)
+			gmin = min;
+		if (max > gmax)
+			gmax = max;
+		gsum += sum;
+		gcount += count;
+
+		printf("%g pps, %Lu.%03Lu %Lu.%03Lu %Lu.%03Lu "
+			"| %Lu.%03Lu %Lu.%03Lu %Lu.%03Lu\n",
+			count / (diff / 1000000000.0),
+			TO_US(min), TO_US(sum / count), TO_US(max),
+			TO_US(gmin), TO_US(gsum / gcount), TO_US(gmax));
+
+		min = ~0ULL;
+		max = 0;
+		sum = 0;
+		count = 0;
+		last_print = now;
+	}
+}
diff --git a/demo/net/mcast-sender.c b/demo/net/mcast-sender.c
new file mode 100644
index 000000000..3e4a083f9
--- /dev/null
+++ b/demo/net/mcast-sender.c
@@ -0,0 +1,151 @@
+/*
+ * sender.c -- multicasts "hello, world!" to a multicast group once a second
+ *
+ * Antony Courtney,	25/11/94
+ */
+
+#include <time.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sched.h>
+#include <pthread.h>
+#include <errno.h>
+#include <signal.h>
+#include <execinfo.h>
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+
+#define HELLO_PORT 12345
+#define HELLO_GROUP "225.0.0.37"
+
+static void check(const char *file, int line, const char *service, int status, int err)
+{
+	if (status >= 0)
+		return;
+
+	pthread_setmode_np(PTHREAD_WARNSW, 0, NULL);
+	__real_fprintf(stderr, "%s:%d: %s: %s\n", file, line, service, strerror(err));
+
+	exit(EXIT_FAILURE);
+}
+
+#define check_pthread(expr)						\
+    ({									\
+	    int _status = (expr);					\
+	    check(__FILE__, __LINE__, #expr, -_status, _status);	\
+    })
+
+#define check_unix(expr)					\
+    ({								\
+	    int _status = (expr);				\
+	    check(__FILE__, __LINE__, #expr, _status, errno);	\
+    })
+
+static const char *reason_str[] = {
+	[SIGDEBUG_UNDEFINED] = "received SIGDEBUG for unknown reason",
+	[SIGDEBUG_MIGRATE_SIGNAL] = "received signal",
+	[SIGDEBUG_MIGRATE_SYSCALL] = "invoked syscall",
+	[SIGDEBUG_MIGRATE_FAULT] = "triggered fault",
+	[SIGDEBUG_MIGRATE_PRIOINV] = "owner is not in real-time mode",
+	[SIGDEBUG_NOMLOCK] = "process memory not locked",
+	[SIGDEBUG_WATCHDOG] = "watchdog triggered (period too short?)",
+	[SIGDEBUG_LOCK_BREAK] = "scheduler lock break",
+	[SIGDEBUG_MUTEX_SLEEP] = "caller sleeps with mutex",
+};
+
+static void sigdebug(int sig, siginfo_t *si, void *context)
+{
+	const char fmt[] = "%s, aborting.\n";
+	unsigned int reason = sigdebug_reason(si);
+	int n __attribute__ ((unused));
+	static char buffer[256];
+	void *bt[32];
+	int nentries;
+
+	if (reason >= sizeof(reason_str) / sizeof(reason_str[0]))
+		reason = SIGDEBUG_UNDEFINED;
+
+	n = snprintf(buffer, sizeof(buffer), fmt, reason_str[reason]);
+	n = write(STDERR_FILENO, buffer, n);
+	nentries = backtrace(bt, sizeof(bt) / sizeof(bt[0]));
+	backtrace_symbols_fd(bt, nentries, STDERR_FILENO);
+
+	signal(sig, SIG_DFL);
+	kill(getpid(), sig);
+}
+
+static void usage(const char *progname)
+{
+	fprintf(stderr, "%s address frequency\n"
+		"Starts sending 'frequency' multicast UDP packets per second on"
+		" the interface\nwith IP address 'address'.\n",
+		progname);
+}
+
+int main(int argc, char *argv[])
+{
+	struct sigaction sa __attribute__((unused));
+	struct sockaddr_in addr;
+	int fd;
+	char message[] = "Hello, World!\n";
+	struct sched_param sparm;
+	struct timespec next;
+	double freq;
+	unsigned period_ns;
+
+	if (argc != 3) {
+		usage(argv[0]);
+		exit(EXIT_FAILURE);
+	}
+
+	freq = atof(argv[2]);
+	period_ns = freq ? 1000000000 / freq : 0;
+
+	check_unix(fd = socket(AF_INET,SOCK_DGRAM, 0));
+
+	addr.sin_addr.s_addr = inet_addr(argv[1]);
+
+	check_unix(setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF,
+				&addr.sin_addr, sizeof(addr.sin_addr)));
+
+	sigemptyset(&sa.sa_mask);
+	sa.sa_sigaction = sigdebug;
+	sa.sa_flags = SA_SIGINFO;
+	check_unix(sigaction(SIGDEBUG, &sa, NULL));
+
+	memset(&addr,0,sizeof(addr));
+	addr.sin_family = AF_INET;
+	addr.sin_addr.s_addr = inet_addr(HELLO_GROUP);
+	addr.sin_port = htons(HELLO_PORT);
+
+	sparm.sched_priority = 99;
+	check_pthread(pthread_setschedparam(pthread_self(),
+						SCHED_FIFO, &sparm));
+
+	check_unix(clock_gettime(CLOCK_MONOTONIC, &next));
+
+	check_pthread(pthread_setmode_np(0, PTHREAD_WARNSW, NULL));
+
+	while (1) {
+		check_unix(sendto(fd,message,sizeof(message), 0,
+					(struct sockaddr *)&addr,
+					sizeof(addr)));
+
+		if (!period_ns)
+			continue;
+
+		next.tv_nsec += period_ns;
+		if (next.tv_nsec >= 1000000000) {
+			next.tv_nsec -= 1000000000;
+			next.tv_sec++;
+		}
+		check_unix(clock_nanosleep(CLOCK_MONOTONIC,
+						TIMER_ABSTIME, &next, NULL));
+	}
+}
diff --git a/demo/net/raw-ethernet.c b/demo/net/raw-ethernet.c
new file mode 100644
index 000000000..f0448d8f6
--- /dev/null
+++ b/demo/net/raw-ethernet.c
@@ -0,0 +1,100 @@
+/***
+ *
+ *  examples/xenomai/posix/raw-ethernet.c
+ *
+ *  SOCK_RAW sender - sends out Ethernet frames via a SOCK_RAW packet socket
+ *
+ *  Copyright (C) 2006 Jan Kiszka <jan.kiszka@web.de>
+ *
+ *  RTnet - real-time networking example
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program 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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <errno.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <netpacket/packet.h>
+#include <net/ethernet.h>
+#include <net/if.h>
+#include <arpa/inet.h>
+
+char buffer[1514];
+int sock;
+
+
+int main(int argc, char *argv[])
+{
+    struct sched_param param = { .sched_priority = 1 };
+    ssize_t len;
+    struct sockaddr_ll addr;
+    struct ifreq ifr;
+    struct timespec delay = { 1, 0 };
+    struct ether_header *eth = (struct ether_header *)buffer;
+
+
+    if (argc < 2) {
+        printf("usage: %s <interface>\n", argv[0]);
+        return 0;
+    }
+
+    if ((sock = socket(PF_PACKET, SOCK_RAW, htons(0x1234))) < 0) {
+        perror("socket cannot be created");
+        return 1;
+    }
+
+    strncpy(ifr.ifr_name, argv[1], IFNAMSIZ-1)[IFNAMSIZ-1] = 0;
+    if (ioctl(sock, SIOCGIFINDEX, &ifr) < 0) {
+        perror("cannot get interface index");
+        close(sock);
+        return 1;
+    }
+
+    addr.sll_family   = AF_PACKET;
+    addr.sll_protocol = htons(0x1234);
+    addr.sll_ifindex  = ifr.ifr_ifindex;
+
+    if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
+        perror("cannot bind to local ip/port");
+        close(sock);
+        return 1;
+    }
+
+    memset(eth->ether_dhost, 0xFF, ETH_HLEN);
+    eth->ether_type = htons(0x1234);
+
+    pthread_setschedparam(pthread_self(), SCHED_FIFO, &param);
+
+    while (1) {
+        len = send(sock, buffer, sizeof(buffer), 0);
+        if (len < 0)
+            break;
+
+        printf("Sent frame of %zd bytes\n", len);
+
+        nanosleep(&delay, NULL);
+    }
+
+    /* This call also leaves primary mode, required for socket cleanup. */
+    printf("shutting down\n");
+
+    return 0;
+}
diff --git a/demo/net/rtt-mcast-measure.c b/demo/net/rtt-mcast-measure.c
new file mode 100644
index 000000000..dc6650645
--- /dev/null
+++ b/demo/net/rtt-mcast-measure.c
@@ -0,0 +1,210 @@
+/*
+ * Multicast RTT sender. Derived from.
+ *
+ * listener.c -- joins a multicast group and echoes all data it receives from
+ *		the group to its stdout...
+ *
+ * Antony Courtney, 	25/11/94
+ * Modified by: Frédéric Bastien (25/03/04)
+ * to compile without warning and work correctly
+ */
+
+#include <stdio.h>
+#include <time.h>
+#include <stdlib.h>
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <alchemy/task.h>
+#include <alchemy/timer.h>
+#include <rtdm/net.h>
+
+#define RTT_PORT 12345
+#define RTT_RECEIVER_GROUP "225.0.0.37"
+#define RTT_SENDER_GROUP "224.0.0.37"
+
+#define rt_inet_aton inet_addr
+#define do_div(ull, u) ({ unsigned long _r = ull % u; ull /= u; _r; })
+
+static int fd;
+
+static void thread(void *arg)
+{
+	unsigned long long gmin, gmax, gsum, gcount;
+	struct sockaddr_in addr, to_addr;
+	RTIME period, start;
+	int i, nbytes, err;
+	socklen_t addrlen;
+	char msgbuf[1500];
+
+	(void)arg;
+
+	memset(&to_addr, 0, sizeof(to_addr));
+	to_addr.sin_family = AF_INET;
+	to_addr.sin_addr.s_addr = rt_inet_aton(RTT_RECEIVER_GROUP);
+	to_addr.sin_port = htons(RTT_PORT);
+
+	start = 0;
+	period = 1000000;
+	err = rt_task_set_periodic(NULL, start, period);
+	if (err < 0) {
+		printf("make_periodic: %d\n", err);
+		rt_task_delete(NULL);
+	}
+
+	gmin = ~0ULL;
+	gmax = 0;
+	gsum = 0;
+	gcount = 0;
+
+	/* now just enter a receive/send loop */
+	for(;;) {
+		unsigned long long smin, smax, ssum, savg, gavg,
+			smin_us, smin_ns, savg_us, savg_ns, smax_us, smax_ns,
+			gmin_us, gmin_ns, gavg_us, gavg_ns, gmax_us, gmax_ns;
+
+		smin = ~0ULL;
+		smax = 0;
+		ssum = 0;
+
+		for (i = 0; i < 1000; i++) {
+			unsigned long overruns;
+			long long rtt;
+
+			err = rt_task_wait_period(&overruns);
+			if (err == -ETIMEDOUT)
+				printf("%ld overruns\n", overruns);
+			else if (err < 0) {
+				printf("wait_period: %d\n", err);
+				rt_task_delete(NULL);
+			}
+
+			rtt = rt_timer_read();
+			err = sendto(fd, msgbuf, 4, 0,
+				(struct sockaddr *)&to_addr, sizeof(to_addr));
+			if (err < 0) {
+				perror("sendto");
+				rt_task_delete(NULL);
+			}
+
+			addrlen = sizeof(addr);
+			nbytes = recvfrom(fd, msgbuf, sizeof(msgbuf), 0,
+					  (struct sockaddr *)&addr, &addrlen);
+			rtt = rt_timer_read() - rtt;
+			if (nbytes <= 0) {
+				perror("recvfrom");
+				rt_task_delete(NULL);
+			}
+
+			if (rtt < smin)
+				smin = rtt;
+			if (rtt > smax)
+				smax = rtt;
+			ssum += rtt;
+		}
+
+		if (smin < gmin)
+			gmin = smin;
+		if (smax > gmax)
+			gmax = smax;
+		gsum += ssum;
+		gcount += 1000;
+
+		savg = ssum + 500;
+		do_div(savg, 1000);
+
+		gavg = gsum + gcount / 2;
+		do_div(gavg, gcount);
+
+		smin_us = smin;
+		smin_ns = do_div(smin_us, 1000);
+
+		savg_us = savg;
+		savg_ns = do_div(savg_us, 1000);
+
+		smax_us = smax;
+		smax_ns = do_div(smax_us, 1000);
+
+		gmin_us = gmin;
+		gmin_ns = do_div(gmin_us, 1000);
+
+		gavg_us = gavg;
+		gavg_ns = do_div(gavg_us, 1000);
+
+		gmax_us = gmax;
+		gmax_ns = do_div(gmax_us, 1000);
+
+		printf("%Lu.%03Lu %Lu.%03Lu %Lu.%03Lu | %Lu.%03Lu %Lu.%03Lu %Lu.%03Lu\n",
+			smin_us, smin_ns, savg_us, savg_ns, smax_us, smax_ns,
+			gmin_us, gmin_ns, gavg_us, gavg_ns, gmax_us, gmax_ns);
+	}
+}
+
+static int create_thread(RT_TASK *tid, int mode, void *arg)
+{
+	struct sockaddr_in addr;
+	struct ip_mreq mreq;
+	int err;
+
+	/* create what looks like an ordinary UDP socket */
+	fd = socket(AF_INET, SOCK_DGRAM, 0);
+	if (fd < 0) {
+		perror("socket");
+		return fd;
+	}
+
+	/* set up destination address */
+	memset(&addr, 0, sizeof(addr));
+	addr.sin_family = AF_INET;
+	if (!arg) {
+		printf("Local ip address expected as first and only argument\n");
+		return -EINVAL;
+	}
+
+	addr.sin_addr.s_addr = rt_inet_aton(arg);
+	addr.sin_port = htons(RTT_PORT);
+
+	/* bind to receive address */
+	err = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
+	if (err < 0) {
+		perror("bind");
+		return err;
+	}
+
+	/* use setsockopt() to request that the kernel join a multicast group */
+	mreq.imr_multiaddr.s_addr = rt_inet_aton(RTT_SENDER_GROUP);
+	mreq.imr_interface.s_addr = addr.sin_addr.s_addr;
+	err = setsockopt(fd, IPPROTO_IP,
+			 IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq));
+	if (err < 0) {
+		perror("setsockopt");
+		rt_task_delete(NULL);
+	}
+
+	err = rt_task_spawn(tid, "rtt-mcast-measure", 8192, 99, mode,
+		thread, NULL);
+	if (err < 0)
+		printf("rt_task_spawn: %d\n", err);
+
+	return err;
+}
+
+int main(int argc, char *argv[])
+{
+	RT_TASK tid;
+	int err;
+
+	err = create_thread(&tid, T_JOINABLE, argc >= 2 ? argv[1] : NULL);
+	if (err)
+		exit(EXIT_FAILURE);
+
+	err = rt_task_join(&tid);
+	if (err < 0)
+		printf("rt_task_join: %d\n", err);
+
+	exit(EXIT_FAILURE);
+}
diff --git a/demo/net/rtt-mcast-responder.c b/demo/net/rtt-mcast-responder.c
new file mode 100644
index 000000000..b8f7dee02
--- /dev/null
+++ b/demo/net/rtt-mcast-responder.c
@@ -0,0 +1,109 @@
+/*
+ * Multicast RTT responder. Derived from.
+ *
+ * listener.c -- joins a multicast group and echoes all data it receives from
+ *		the group to its stdout...
+ *
+ * Antony Courtney, 	25/11/94
+ * Modified by: Frédéric Bastien (25/03/04)
+ * to compile without warning and work correctly
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+#include <string.h>
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <pthread.h>
+#include <rtdm/net.h>
+
+
+#define RTT_PORT 12345
+#define RTT_RECEIVER_GROUP "225.0.0.37"
+#define RTT_SENDER_GROUP "224.0.0.37"
+
+int main(int argc, char *argv[])
+{
+	struct sockaddr_in addr, to_addr;
+	struct sched_param sparm;
+	int add_rtskbs = 128;
+	struct ip_mreq mreq;
+	int fd, err, nbytes;
+	socklen_t addrlen;
+	char msgbuf[1500];
+
+	sparm.sched_priority = 99;
+	err = pthread_setschedparam(pthread_self(), SCHED_FIFO, &sparm);
+	if (err) {
+		fprintf(stderr, "pthread_setschedparam: %d\n", err);
+		exit(EXIT_FAILURE);
+	}
+
+	/* create what looks like an ordinary UDP socket */
+	fd = socket(AF_INET, SOCK_DGRAM, 0);
+	if (fd < 0) {
+		perror("socket");
+		exit(EXIT_FAILURE);
+	}
+
+	/* set up destination address */
+	memset(&addr, 0, sizeof(addr));
+	addr.sin_family = AF_INET;
+	if (argc != 2) {
+		fprintf(stderr, "Local ip address expected as first and only argument\n");
+		exit(EXIT_FAILURE);
+	}
+
+	addr.sin_addr.s_addr = inet_addr(argv[1]);
+	addr.sin_port = htons(RTT_PORT);
+
+	/* bind to receive address */
+	err = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
+	if (err < 0) {
+		perror("bind");
+		exit(EXIT_FAILURE);
+	}
+
+	memset(&to_addr, 0, sizeof(to_addr));
+	to_addr.sin_family = AF_INET;
+	to_addr.sin_addr.s_addr = inet_addr(RTT_SENDER_GROUP);
+	to_addr.sin_port = htons(RTT_PORT);
+
+	/* use setsockopt() to request that the kernel join a multicast group */
+	mreq.imr_multiaddr.s_addr = inet_addr(RTT_RECEIVER_GROUP);
+	mreq.imr_interface.s_addr = addr.sin_addr.s_addr;
+	err = setsockopt(fd, IPPROTO_IP,
+			IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq));
+	if (err < 0) {
+		perror("setsockopt");
+		exit(EXIT_FAILURE);
+	}
+
+	err = ioctl(fd, RTNET_RTIOC_EXTPOOL, &add_rtskbs);
+	if (err < 0)
+		perror("ioctl(RTNET_RTIOC_EXTPOOL)\n");
+
+	/* now just enter a receive/send loop */
+	while (1) {
+		addrlen = sizeof(addr);
+		nbytes = recvfrom(fd, msgbuf, sizeof(msgbuf), 0,
+				(struct sockaddr *)&addr, &addrlen);
+		if (nbytes <= 0) {
+			perror("recvfrom");
+			exit(EXIT_FAILURE);
+		}
+
+		err = sendto(fd, msgbuf, nbytes, 0,
+			(struct sockaddr *)&to_addr, sizeof(addr));
+		if (err < 0) {
+			perror("sendto");
+			exit(EXIT_FAILURE);
+		}
+	}
+}
diff --git a/demo/net/rtt-responder.c b/demo/net/rtt-responder.c
new file mode 100644
index 000000000..6e31a1ff2
--- /dev/null
+++ b/demo/net/rtt-responder.c
@@ -0,0 +1,193 @@
+/***
+ *
+ *  examples/xenomai/posix/rtt-responder.c
+ *
+ *  Round-Trip Time Responder - listens and sends back a packet
+ *
+ *  Based on Ulrich Marx's module, later ported over user space POSIX.
+ *
+ *  Copyright (C) 2002 Ulrich Marx <marx@kammer.uni-hannover.de>
+ *                2002 Marc Kleine-Budde <kleine-budde@gmx.de>
+ *                2004, 2006 Jan Kiszka <jan.kiszka@web.de>
+ *
+ *  RTnet - real-time networking example
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program 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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <errno.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <string.h>
+#include <unistd.h>
+#include <netinet/in.h>
+#include <sys/mman.h>
+#include <arpa/inet.h>
+#include <limits.h>
+
+#include <rtdm/net.h>
+
+char *dest_ip_s = "";
+char *local_ip_s  = "";
+unsigned int reply_size = 0;
+
+pthread_t rt_thread;
+
+#define RCV_PORT    36000
+#define XMT_PORT    35999
+
+struct sockaddr_in dest_addr;
+
+int sock;
+
+char buffer[65536];
+
+
+static void *responder(void* arg)
+{
+    struct sched_param  param = { .sched_priority = 81 };
+    struct msghdr       rx_msg;
+    struct iovec        iov;
+    ssize_t             ret;
+
+
+    if (dest_addr.sin_addr.s_addr == INADDR_ANY) {
+        rx_msg.msg_name    = &dest_addr;
+        rx_msg.msg_namelen = sizeof(dest_addr);
+    } else {
+        rx_msg.msg_name    = NULL;
+        rx_msg.msg_namelen = 0;
+    }
+    rx_msg.msg_namelen     = sizeof(struct sockaddr_in);
+    rx_msg.msg_iov         = &iov;
+    rx_msg.msg_iovlen      = 1;
+    rx_msg.msg_control     = NULL;
+    rx_msg.msg_controllen  = 0;
+
+    pthread_setschedparam(pthread_self(), SCHED_FIFO, &param);
+
+    while(1) {
+        iov.iov_base = &buffer;
+        iov.iov_len  = sizeof(buffer);
+
+        ret = recvmsg(sock, &rx_msg, 0);
+        if (ret <= 0) {
+            printf("terminating responder thread\n");
+            return NULL;
+        }
+
+        sendto(sock, &buffer, reply_size ? : ret, 0,
+               (struct sockaddr *)&dest_addr,
+               sizeof(struct sockaddr_in));
+    }
+}
+
+
+int main(int argc, char *argv[])
+{
+    struct sockaddr_in local_addr;
+    int add_rtskbs = 30;
+    pthread_attr_t thattr;
+    int ret;
+
+
+    while (1) {
+        switch (getopt(argc, argv, "d:l:s:")) {
+            case 'd':
+                dest_ip_s = optarg;
+                break;
+
+            case 'l':
+                local_ip_s = optarg;
+                break;
+
+            case 's':
+                reply_size = atoi(optarg);
+                break;
+
+            case -1:
+                goto end_of_opt;
+
+            default:
+                printf("usage: %s [-d <dest_ip>] [-l <local_ip>] "
+                       "[-s <reply_size>]\n", argv[0]);
+                return 0;
+        }
+    }
+ end_of_opt:
+
+    if (dest_ip_s[0]) {
+        inet_aton(dest_ip_s, &dest_addr.sin_addr);
+        dest_addr.sin_port = htons(XMT_PORT);
+    } else
+        dest_addr.sin_addr.s_addr = INADDR_ANY;
+
+    if (local_ip_s[0])
+        inet_aton(local_ip_s, &local_addr.sin_addr);
+    else
+        local_addr.sin_addr.s_addr = INADDR_ANY;
+
+    if (reply_size > 65505)
+        reply_size = 65505;
+    else if (reply_size < sizeof(struct timespec))
+        reply_size = sizeof(struct timespec);
+
+    printf("destination ip address: %s = %08x\n",
+           dest_ip_s[0] ? dest_ip_s : "SENDER", dest_addr.sin_addr.s_addr);
+    printf("local ip address: %s = %08x\n",
+           local_ip_s[0] ? local_ip_s : "INADDR_ANY", local_addr.sin_addr.s_addr);
+    printf("reply size: %d\n", reply_size);
+
+    /* create rt-socket */
+    if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
+        perror("socket cannot be created");
+        return 1;
+    }
+
+    /* bind the rt-socket to local_addr */
+    local_addr.sin_family = AF_INET;
+    local_addr.sin_port   = htons(RCV_PORT);
+    if (bind(sock, (struct sockaddr *)&local_addr, sizeof(local_addr)) < 0) {
+        perror("cannot bind to local ip/port");
+        close(sock);
+        return 1;
+    }
+
+    /* extend the socket pool */
+    ret = ioctl(sock, RTNET_RTIOC_EXTPOOL, &add_rtskbs);
+    if (ret < 0)
+        perror("ioctl(RTNET_RTIOC_EXTPOOL)\n");
+
+    /* create reply rt-thread */
+    pthread_attr_init(&thattr);
+    pthread_attr_setdetachstate(&thattr, PTHREAD_CREATE_JOINABLE);
+    pthread_attr_setstacksize(&thattr, PTHREAD_STACK_MIN);
+    ret = pthread_create(&rt_thread, &thattr, &responder, NULL);
+    if (ret) {
+        close(sock);
+        errno = ret; perror("pthread_create failed");
+        return 1;
+    }
+
+    pause();
+
+    pthread_kill(rt_thread, SIGHUP);
+    pthread_join(rt_thread, NULL);
+
+    return 0;
+}
diff --git a/demo/net/rtt-sender.c b/demo/net/rtt-sender.c
new file mode 100644
index 000000000..ae75a6f19
--- /dev/null
+++ b/demo/net/rtt-sender.c
@@ -0,0 +1,341 @@
+/***
+ *
+ *  examples/xenomai/posix/rtt-requester.c
+ *
+ *  Round-Trip Time Requester - sends packet, receives echo, evaluates
+ *                              and displays per-station round-trip times
+ *
+ *  Based on Ulrich Marx's module, adopted to RTmac and later ported over
+ *  user space POSIX.
+ *
+ *  Copyright (C) 2002 Ulrich Marx <marx@kammer.uni-hannover.de>
+ *                2002 Marc Kleine-Budde <kleine-budde@gmx.de>
+ *                2006 Jan Kiszka <jan.kiszka@web.de>
+ *
+ *  RTnet - real-time networking example
+ *  RTmac - real-time media access control example
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program 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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <errno.h>
+#include <mqueue.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <string.h>
+#include <unistd.h>
+#include <netinet/in.h>
+#include <sys/mman.h>
+#include <arpa/inet.h>
+#include <limits.h>
+
+#include <rtdm/net.h>
+
+char *dest_ip_s = "127.0.0.1";
+char *local_ip_s = "";
+unsigned int cycle = 50000; /* 50 ms */
+
+pthread_t xmit_thread;
+pthread_t recv_thread;
+
+#define RCV_PORT                35999
+#define XMT_PORT                36000
+
+#define DEFAULT_ADD_BUFFERS     30
+
+struct sockaddr_in dest_addr;
+
+int sock;
+mqd_t mq;
+
+#define BUFSIZE 1500
+union {
+    char            data[BUFSIZE];
+    struct timespec tx_date;
+} packet;
+
+struct station_stats {
+    struct in_addr  addr;
+    long long       last, min, max;
+    unsigned long   count;
+};
+
+struct packet_stats {
+    struct in_addr  addr;
+    long long       rtt;
+};
+
+#define MAX_STATIONS 100
+static struct station_stats station[MAX_STATIONS];
+
+
+static struct station_stats *lookup_stats(struct in_addr addr)
+{
+    int i;
+
+    for (i = 0; i < MAX_STATIONS; i++) {
+        if (station[i].addr.s_addr == addr.s_addr)
+            break;
+        if (station[i].addr.s_addr == 0) {
+            station[i].addr = addr;
+            station[i].min  = LONG_MAX;
+            station[i].max  = LONG_MIN;
+            break;
+        }
+    }
+    if (i == MAX_STATIONS)
+        return NULL;
+    return &station[i];
+}
+
+
+static void *transmitter(void *arg)
+{
+    struct sched_param  param = { .sched_priority = 80 };
+    struct timespec     next_period;
+    struct timespec     tx_date;
+
+
+    pthread_setschedparam(pthread_self(), SCHED_FIFO, &param);
+
+    clock_gettime(CLOCK_MONOTONIC, &next_period);
+
+    while(1) {
+        next_period.tv_nsec += cycle * 1000;
+        if (next_period.tv_nsec >= 1000000000) {
+            next_period.tv_nsec = 0;
+            next_period.tv_sec++;
+        }
+
+        clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &next_period, NULL);
+
+        clock_gettime(CLOCK_MONOTONIC, &tx_date);
+
+        /* transmit the request packet containing the local time */
+        if (sendto(sock, &tx_date, sizeof(tx_date), 0,
+                   (struct sockaddr *)&dest_addr,
+                   sizeof(struct sockaddr_in)) < 0) {
+            if (errno == EBADF)
+                printf("terminating transmitter thread\n");
+            else
+                perror("sendto failed");
+            return NULL;
+        }
+    }
+}
+
+
+static void *receiver(void *arg)
+{
+    struct sched_param  param = { .sched_priority = 82 };
+    struct msghdr       msg;
+    struct iovec        iov;
+    struct sockaddr_in  addr;
+    struct timespec     rx_date;
+    struct packet_stats stats;
+    int                 ret;
+
+
+    msg.msg_name       = &addr;
+    msg.msg_namelen    = sizeof(addr);
+    msg.msg_iov        = &iov;
+    msg.msg_iovlen     = 1;
+    msg.msg_control    = NULL;
+    msg.msg_controllen = 0;
+
+    pthread_setschedparam(pthread_self(), SCHED_FIFO, &param);
+
+    while (1) {
+        iov.iov_base = &packet;
+        iov.iov_len  = sizeof(packet);
+
+        ret = recvmsg(sock, &msg, 0);
+        if (ret <= 0) {
+            printf("terminating receiver thread\n");
+            return NULL;
+        }
+
+        clock_gettime(CLOCK_MONOTONIC, &rx_date);
+        stats.rtt = rx_date.tv_sec * 1000000000LL + rx_date.tv_nsec;
+        stats.rtt -= packet.tx_date.tv_sec * 1000000000LL +
+            packet.tx_date.tv_nsec;
+        stats.addr = addr.sin_addr;
+
+        mq_send(mq, (char *)&stats, sizeof(stats), 0);
+    }
+}
+
+
+int main(int argc, char *argv[])
+{
+    struct sched_param param = { .sched_priority = 1 };
+    struct sockaddr_in local_addr;
+    int add_rtskbs = DEFAULT_ADD_BUFFERS;
+    pthread_attr_t thattr;
+    char mqname[32];
+    struct mq_attr mqattr;
+    int stations = 0;
+    int ret;
+
+
+    while (1) {
+        switch (getopt(argc, argv, "d:l:c:b:")) {
+            case 'd':
+                dest_ip_s = optarg;
+                break;
+
+            case 'l':
+                local_ip_s = optarg;
+                break;
+
+            case 'c':
+                cycle = atoi(optarg);
+                break;
+
+            case 'b':
+                add_rtskbs = atoi(optarg);
+
+            case -1:
+                goto end_of_opt;
+
+            default:
+                printf("usage: %s [-d <dest_ip>] [-l <local_ip>] "
+                       "[-c <cycle_microsecs>] [-b <add_buffers>]\n",
+                       argv[0]);
+                return 0;
+        }
+    }
+ end_of_opt:
+
+    dest_addr.sin_family = AF_INET;
+    dest_addr.sin_port   = htons(XMT_PORT);
+    if (dest_ip_s[0])
+        inet_aton(dest_ip_s, &dest_addr.sin_addr);
+    else
+        dest_addr.sin_addr.s_addr = INADDR_ANY;
+
+    if (local_ip_s[0])
+        inet_aton(local_ip_s, &local_addr.sin_addr);
+    else
+        local_addr.sin_addr.s_addr = INADDR_ANY;
+
+    printf("destination ip address: %s = %08x\n",
+           dest_ip_s[0] ? dest_ip_s : "SENDER", dest_addr.sin_addr.s_addr);
+    printf("local ip address: %s = %08x\n",
+           local_ip_s[0] ? local_ip_s : "INADDR_ANY", local_addr.sin_addr.s_addr);
+    printf("cycle: %d us\n", cycle);
+
+    /* create rt-socket */
+    if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
+        perror("socket cannot be created");
+        return 1;
+    }
+
+    /* bind the rt-socket to local_addr */
+    local_addr.sin_family = AF_INET;
+    local_addr.sin_port   = htons(RCV_PORT);
+    if (bind(sock, (struct sockaddr *)&local_addr, sizeof(local_addr)) < 0) {
+        perror("cannot bind to local ip/port");
+        close(sock);
+        return 1;
+    }
+
+    /* extend the socket pool */
+    ret = ioctl(sock, RTNET_RTIOC_EXTPOOL, &add_rtskbs);
+    if (ret < 0)
+        perror("ioctl(RTNET_RTIOC_EXTPOOL)");
+
+    /* create statistics message queue */
+    snprintf(mqname, sizeof(mqname), "/rtt-sender-%d", getpid());
+    mqattr.mq_flags   = 0;
+    mqattr.mq_maxmsg  = 100;
+    mqattr.mq_msgsize = sizeof(struct packet_stats);
+    mq = mq_open(mqname, O_RDWR | O_CREAT | O_EXCL, 0600, &mqattr);
+    if (mq == (mqd_t)-1) {
+        perror("opening mqueue failed");
+        close(sock);
+        return 1;
+    }
+
+    /* create transmitter rt-thread */
+    pthread_attr_init(&thattr);
+    pthread_attr_setdetachstate(&thattr, PTHREAD_CREATE_JOINABLE);
+    pthread_attr_setstacksize(&thattr, PTHREAD_STACK_MIN);
+    ret = pthread_create(&recv_thread, &thattr, &receiver, NULL);
+    if (ret) {
+        errno = ret; perror("pthread_create(receiver) failed");
+        close(sock);
+        mq_close(mq);
+        return 1;
+    }
+
+    /* create receiver rt-thread */
+    ret = pthread_create(&xmit_thread, &thattr, &transmitter, NULL);
+    if (ret) {
+        errno = ret; perror("pthread_create(transmitter) failed");
+        close(sock);
+        mq_close(mq);
+        pthread_kill(recv_thread, SIGHUP);
+        pthread_join(recv_thread, NULL);
+        return 1;
+    }
+
+    pthread_setschedparam(pthread_self(), SCHED_FIFO, &param);
+
+    while (1) {
+        struct packet_stats pack;
+        struct station_stats *pstat;
+        int nr;
+
+        ret = mq_receive(mq, (char *)&pack, sizeof(pack), NULL);
+        if (ret < (int)sizeof(pack))
+            break;
+
+        pstat = lookup_stats(pack.addr);
+        if (!pstat)
+            continue;
+
+        pstat->last = pack.rtt;
+        if (pstat->last < pstat->min)
+            pstat->min = pstat->last;
+        if (pstat->last > pstat->max)
+            pstat->max = pstat->last;
+        pstat->count++;
+
+        nr = pstat - &station[0];
+        if (nr >= stations) {
+            stations = nr+1;
+            printf("\n");
+        }
+
+        printf("\033[%dA%s\t%9.3f us, min=%9.3f us, max=%9.3f us, count=%ld\n",
+               stations-nr, inet_ntoa(pack.addr), (float)pstat->last/1000,
+               (float)pstat->min/1000, (float)pstat->max/1000, pstat->count);
+        for (nr = stations-nr-1; nr > 0; nr --)
+            printf("\n");
+    }
+
+    /* This call also leaves primary mode, required for socket cleanup. */
+    printf("shutting down\n");
+
+    pthread_join(xmit_thread, NULL);
+    pthread_kill(recv_thread, SIGHUP);
+    pthread_join(recv_thread, NULL);
+
+    return 0;
+}
diff --git a/demo/net/rttcp-client.c b/demo/net/rttcp-client.c
new file mode 100644
index 000000000..e7da36b91
--- /dev/null
+++ b/demo/net/rttcp-client.c
@@ -0,0 +1,212 @@
+/***
+ *
+ *  examples/xenomai/posix/rttcp-client.c
+ *
+ *  Simple RTNet TCP client - sends packet to a server
+ *
+ *  Copyright (C) 2009 Vladimir Zapolskiy <vladimir.zapolskiy@siemens.com>
+ *
+ *  RTnet - real-time networking example
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License, version 2, as
+ *  published by the Free Software Foundation.
+ *
+ *  This program 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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <netinet/in.h>
+#include <sys/mman.h>
+#include <arpa/inet.h>
+#include <limits.h>
+
+#include <rtdm/net.h>
+
+char *dest_ip_s = "127.0.0.1";
+char *local_ip_s = "";
+unsigned int cycle = 500000; /* 500 ms */
+
+#define RCV_PORT                35999
+#define XMT_PORT                36000
+#define DEFAULT_LOOPS           10
+#define DEFAULT_ADD_BUFFERS     30
+
+int add_rtskbs = DEFAULT_ADD_BUFFERS;
+
+pthread_t sender_task = 0;
+
+struct conn_t {
+    int nloops;
+    int sock;
+    struct sockaddr_in dest_addr;
+    struct sockaddr_in local_addr;
+};
+
+const char msg[] = "Hello";
+
+static void *sender(void *arg)
+{
+    struct conn_t *connection = (struct conn_t *)arg;
+    int sock = connection->sock;
+    int ret, i, sopt_len;
+    struct timeval  tv;
+    struct timespec sleep_period;
+
+    sopt_len = 1;
+    if ((ret = setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &sopt_len,
+                          sizeof(sopt_len))) < 0) {
+        perror("set SO_KEEPALIVE socket option");
+        return NULL;
+    }
+
+    tv.tv_sec = 0;
+    tv.tv_usec = 100000;
+    if ((ret = setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, &tv,
+                          sizeof(tv))) < 0) {
+        perror("set SO_SNDTIMEO socket option");
+        return NULL;
+    }
+
+    if ((ret = bind(sock, (struct sockaddr*)&connection->local_addr,
+        sizeof(struct sockaddr_in))) < 0)
+    {
+        perror("bind socket");
+        return NULL;
+    }
+
+    if ((ret = connect(sock, (struct sockaddr*)&connection->dest_addr,
+        sizeof(struct sockaddr_in))) < 0)
+    {
+        perror("connect to server");
+        return NULL;
+    }
+
+    sleep_period.tv_nsec = cycle * 1000;
+
+    for (i = 1; i <= connection->nloops; i++) {
+        clock_gettime(CLOCK_MONOTONIC, &sleep_period);
+
+        sleep_period.tv_nsec += cycle * 1000;
+        if (sleep_period.tv_nsec >= 1000000000) {
+            sleep_period.tv_nsec = 0;
+            sleep_period.tv_sec++;
+        }
+
+        ret = write(sock, msg, sizeof(msg));
+        if (ret <= 0) {
+            if (ret == 0)
+                printf("connection closed by peer\n");
+            else
+                perror("write to socket");
+            return NULL;
+        }
+        printf("%d: wrote %d bytes to socket\n", i, ret);
+
+        clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &sleep_period, NULL);
+    }
+
+    return NULL;
+}
+
+int main(int argc, char** argv)
+{
+    struct conn_t connection = { .nloops = DEFAULT_LOOPS };
+    struct sched_param param;
+    pthread_attr_t attr;
+    int local_port = RCV_PORT;
+    int ret;
+
+    while (1) {
+        switch (getopt(argc, argv, "d:l:p:n:")) {
+            case 'd':
+                dest_ip_s = optarg;
+                break;
+
+            case 'l':
+                local_ip_s = optarg;
+                break;
+
+            case 'p':
+                local_port = atoi(optarg);
+                break;
+
+            case 'n':
+                connection.nloops = atoi(optarg);
+                break;
+
+            case -1:
+                goto end_of_opt;
+
+            default:
+                printf("usage: %s [-d <dest_ip>] [-l <local_ip>] "
+                       "[-p <local port>] [-n <number of loops>]\n", argv[0]);
+                return 0;
+        }
+    }
+ end_of_opt:
+
+    connection.dest_addr.sin_family = AF_INET;
+    connection.dest_addr.sin_port   = htons(XMT_PORT);
+    if (dest_ip_s[0])
+        inet_aton(dest_ip_s, &connection.dest_addr.sin_addr);
+    else
+        connection.dest_addr.sin_addr.s_addr = INADDR_ANY;
+
+    connection.local_addr.sin_family = AF_INET;
+    connection.local_addr.sin_port = htons(local_port);
+    if (local_ip_s[0])
+        inet_aton(local_ip_s, &connection.local_addr.sin_addr);
+    else
+        connection.local_addr.sin_addr.s_addr = INADDR_ANY;
+
+    printf("destination ip address: %s = %08x\n",
+           dest_ip_s[0] ? dest_ip_s : "SENDER",
+           connection.dest_addr.sin_addr.s_addr);
+    printf("local ip address: %s = %08x\n",
+           local_ip_s[0] ? local_ip_s : "INADDR_ANY",
+           connection.local_addr.sin_addr.s_addr);
+    printf("port: %d\n", local_port);
+
+    /* create rt-socket */
+    if ((connection.sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
+        perror("socket create");
+        return 1;
+    }
+
+    /* extend the socket pool (optional, will fail with non-RT sockets) */
+    ret = ioctl(connection.sock, RTNET_RTIOC_EXTPOOL, &add_rtskbs);
+    if (ret < 0)
+        perror("ioctl(RTNET_RTIOC_EXTPOOL)");
+
+    pthread_attr_init(&attr);
+    pthread_attr_setinheritsched(&attr, 1);
+    pthread_attr_setschedpolicy(&attr, SCHED_FIFO);
+    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
+    pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN);
+    param.sched_priority = 80;
+    pthread_attr_setschedparam(&attr, &param);
+
+    ret = pthread_create(&sender_task, &attr, &sender, &connection);
+    if (ret) {
+        perror("start real-time task");
+        return 1;
+    }
+
+    pthread_join(sender_task, NULL);
+    close(connection.sock);
+
+    return 0;
+}
diff --git a/demo/net/rttcp-server.c b/demo/net/rttcp-server.c
new file mode 100644
index 000000000..d6422e60e
--- /dev/null
+++ b/demo/net/rttcp-server.c
@@ -0,0 +1,181 @@
+/***
+ *
+ *  examples/xenomai/posix/rttcp-server.c
+ *
+ *  Simple RTNet TCP server - listens and sends back a packet
+ *
+ *  Copyright (C) 2009 Vladimir Zapolskiy <vladimir.zapolskiy@siemens.com>
+ *
+ *  RTnet - real-time networking example
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License, version 2, as
+ *  published by the Free Software Foundation.
+ *
+ *  This program 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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <netinet/in.h>
+#include <sys/mman.h>
+#include <arpa/inet.h>
+#include <limits.h>
+
+#include <rtdm/net.h>
+
+char *local_ip_s  = "";
+
+#define RCV_PORT            36000
+#define MAX_STRLENGTH       128
+#define DEFAULT_ADD_BUFFERS 30
+
+int add_rtskbs = DEFAULT_ADD_BUFFERS;
+
+pthread_t receiver_task = 0;
+
+struct conn_t {
+    int sock;
+    struct sockaddr_in client_addr;
+    struct sockaddr_in local_addr;
+};
+
+static void* receiver(void* arg)
+{
+    struct conn_t *connection = (struct conn_t*)arg;
+    socklen_t len = sizeof(struct sockaddr_in);
+    int sock = connection->sock;
+    struct timeval tv;
+    fd_set readset;
+    int cnt = 0;
+    char chr;
+    int ret;
+
+    /* bind the rt-socket to local_addr */
+    connection->local_addr.sin_family = AF_INET;
+    connection->local_addr.sin_port   = htons(RCV_PORT);
+    if (bind(sock, (struct sockaddr *)&connection->local_addr,
+             sizeof(struct sockaddr_in)) < 0) {
+        perror("bind socket");
+        return NULL;
+    }
+
+    /* Backlog is ignored, current realization just transmit state to LISTEN */
+    if (listen(sock, 1) < 0) {
+        perror("listen on socket");
+        return NULL;
+    }
+
+    /* Warning, no new socket descriptor, only one connection */
+    sock = accept(sock, (struct sockaddr *)&connection->client_addr, &len);
+    if (sock < 0) {
+        perror("accept connection");
+        return NULL;
+    }
+    printf("connection from %s:%d\n",
+           inet_ntoa(connection->client_addr.sin_addr),
+           ntohs(connection->client_addr.sin_port));
+
+    while (1) {
+        FD_ZERO(&readset);
+        FD_SET(sock, &readset);
+        tv.tv_sec = 5;
+        tv.tv_usec = 0;
+
+        ret = select(sock + 1, &readset, NULL, NULL, &tv);
+        if (ret <= 0) {
+            if (ret == 0)
+                fprintf(stderr, "timeout during select()\n");
+            else
+                perror("error on select()");
+            return NULL;
+        }
+
+        if (FD_ISSET(sock, &readset)) {
+            ret = read(sock, &chr, 1);
+            if (ret <= 0) {
+                if (ret == 0)
+                    printf("connection closed\n");
+                else
+                    perror("error on read()");
+                return NULL;
+            }
+
+            printf("%d: received %d bytes, message: %c\n", cnt++, ret, chr);
+        }
+    }
+    return NULL;
+}
+
+int main(int argc, char** argv)
+{
+    struct conn_t connection;
+    struct sched_param param;
+    pthread_attr_t attr;
+    int ret;
+
+    while (1) {
+        switch (getopt(argc, argv, "l:")) {
+            case 'l':
+                local_ip_s = optarg;
+                break;
+
+            case -1:
+                goto end_of_opt;
+
+            default:
+                printf("usage: %s [-l <local_ip>]\n", argv[0]);
+                return 0;
+        }
+    }
+ end_of_opt:
+
+    if (local_ip_s[0])
+        inet_aton(local_ip_s, &connection.local_addr.sin_addr);
+    else
+        connection.local_addr.sin_addr.s_addr = INADDR_ANY;
+
+    printf("local ip address: %s = %08x\n",
+           local_ip_s[0] ? local_ip_s : "INADDR_ANY",
+           connection.local_addr.sin_addr.s_addr);
+
+    /* create rt-socket */
+    if ((connection.sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
+        perror("socket create");
+        return 1;
+    }
+
+    /* extend the socket pool (optional, will fail with non-RT sockets) */
+    ret = ioctl(connection.sock, RTNET_RTIOC_EXTPOOL, &add_rtskbs);
+    if (ret < 0)
+        perror("ioctl(RTNET_RTIOC_EXTPOOL)");
+
+    pthread_attr_init(&attr);
+    pthread_attr_setinheritsched(&attr, 1);
+    pthread_attr_setschedpolicy(&attr, SCHED_FIFO);
+    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
+    pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN);
+    param.sched_priority = 20;
+    pthread_attr_setschedparam(&attr, &param);
+
+    ret = pthread_create(&receiver_task, NULL, &receiver, &connection);
+    if (ret) {
+        perror("start real-time task");
+        return 1;
+    }
+
+    pthread_join(receiver_task, NULL);
+    close(connection.sock);
+
+    return 0;
+}
diff --git a/demo/net/udp-send.c b/demo/net/udp-send.c
new file mode 100644
index 000000000..a29f98024
--- /dev/null
+++ b/demo/net/udp-send.c
@@ -0,0 +1,136 @@
+/*
+ * sender.c -- multicasts "hello, world!" to a multicast group once a second
+ *
+ * Antony Courtney,	25/11/94
+ */
+
+#include <time.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <error.h>
+#include <stdlib.h>
+#include <sched.h>
+#include <pthread.h>
+#include <sys/timerfd.h>
+#include <boilerplate/trace.h>
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+
+#define HELLO_PORT 12345
+#define HELLO_GROUP "225.0.0.37"
+#define ONE_BILLION	1000000000
+
+#define check_pthread(expr)			\
+	({ \
+		int __e = (expr);		\
+		if (__e) {			\
+			printf("%s: %d\n", #expr, __e);	\
+			exit(EXIT_FAILURE);		\
+		}					\
+	})
+
+int main(int argc, char *argv[])
+{
+     struct sockaddr_in addr;
+     int fd, tfd, err;
+     char message[] = "Hello, World!\n";
+     struct timespec last_print, start, now;
+     struct sched_param sparm;
+     unsigned long long diff, min = ~0ULL, max = 0, sum, count;
+     struct itimerspec timer_conf;
+
+     /* create what looks like an ordinary UDP socket */
+     if ((fd=socket(AF_INET,SOCK_DGRAM,0)) < 0) {
+	  perror("socket");
+	  exit(1);
+     }
+
+     if (argc != 2) {
+	 fprintf(stderr, "Local ip address expected as first and only argument\n");
+	 exit(1);
+     }
+
+     memset(&addr,0,sizeof(addr));
+     addr.sin_family=AF_INET;
+     addr.sin_addr.s_addr=inet_addr(argv[1]); /* N.B.: differs from sender */
+     addr.sin_port=htons(HELLO_PORT);
+
+     /* bind to receive address */
+     if (bind(fd,(struct sockaddr *) &addr,sizeof(addr)) < 0) {
+	  perror("bind");
+	  exit(1);
+     }
+
+     /* set up destination address */
+     memset(&addr,0,sizeof(addr));
+     addr.sin_family=AF_INET;
+     addr.sin_addr.s_addr=inet_addr(HELLO_GROUP);
+     addr.sin_port=htons(HELLO_PORT);
+
+     sparm.sched_priority = 99;
+
+     check_pthread(pthread_setschedparam(pthread_self(), SCHED_FIFO, &sparm));
+
+     tfd = timerfd_create(CLOCK_MONOTONIC, 0);
+     if (tfd == -1)
+	     error(1, errno, "timerfd_create()");
+
+     check_pthread(pthread_setmode_np(0, PTHREAD_WARNSW, NULL));
+
+     /* now just sendto() our destination! */
+     sum = 0;
+     count = 0;
+     err = clock_gettime(CLOCK_MONOTONIC, &start);
+     start.tv_nsec += 1000000;
+     if (start.tv_nsec > ONE_BILLION) {
+	     start.tv_nsec -= ONE_BILLION;
+	     start.tv_sec++;
+     }
+     timer_conf.it_value = start;
+     timer_conf.it_interval.tv_sec = 0;
+     timer_conf.it_interval.tv_nsec = 5000000;
+     err = timerfd_settime(tfd, TFD_TIMER_ABSTIME, &timer_conf, NULL);
+     if (err)
+	     error(1, errno, "timerfd_settime()");
+     clock_gettime(CLOCK_MONOTONIC, &last_print);
+
+     while (1) {
+	     uint64_t ticks;
+	     clock_gettime(CLOCK_MONOTONIC, &start);
+	     if (sendto(fd,message,sizeof(message),0,(struct sockaddr *) &addr,
+			     sizeof(addr)) < 0) {
+		     perror("sendto");
+		     exit(1);
+	     }
+	     clock_gettime(CLOCK_MONOTONIC, &now);
+
+	     diff = now.tv_sec * 1000000ULL + now.tv_nsec / 1000 -
+		     (start.tv_sec * 1000000ULL + start.tv_nsec / 1000);
+	     if (diff < min)
+		     min = diff;
+	     if (diff > max) {
+		     xntrace_user_freeze(diff, 0);
+		     max = diff;
+	     }
+	     sum += diff;
+	     count++;
+
+	     diff = now.tv_sec * 1000000ULL + now.tv_nsec / 1000 -
+		     (last_print.tv_sec * 1000000ULL + last_print.tv_sec / 1000);
+	     if (diff >= 1000000) {
+		     fprintf(stderr, "%Lu, %Lu, %Lu\n",
+			     min, sum / count, max);
+		     last_print = now;
+	     }
+
+	     err = read(tfd, &ticks, sizeof(ticks));
+	     if (err < 0)
+		     error(1, errno, "read()");
+     }
+}
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 19+ messages in thread

* Still More Slackspot Issues - Patch Included
  2019-03-21 17:13 ` [PATCH 16/16] demo/net: add rtnet tests Philippe Gerum
@ 2019-03-21 23:31   ` Stephen D. Cohen
  2019-03-22 15:51     ` Philippe Gerum
  0 siblings, 1 reply; 19+ messages in thread
From: Stephen D. Cohen @ 2019-03-21 23:31 UTC (permalink / raw)
  To: xenomai

Folks,

     Some time back I submitted a patch for the slackspot issue
regarding when to remove the vm_start offset from the program counter
in the relax handling mechanism in debug.c. My solution had the
unfortunate flaw that it peeked into the actual ELF section headers in
the running system (ewww...) and was deemed unworthy. The solution
that got implemented, using VM_DENYWRITE to detect dynamic objects,
has the unfortunate flaw of not working with position independent
executable programs. The very problem that got me started in the first
place.

     As luck would have it, I recently needed slackspot to figure out
some issues with our application. So I set out to make it work again.
In the process, I also found another issue - when the target
application uses inline routines, all the spots in the same file past
the inlined routine are reported incorrectly. This is due to slackspot
assuming a 1:1 mapping between addresses and reported results. The
inlined routines actually report two sets of results for each address.

     So I propose the attached solution. Move the trouble of
identifying the ELF object type out of the kernel and put it in
slackspot instead. Just store both the pc and vm_start for every spot,
then figure it all out in slackspot. Slackspot then uses elfread to
determine if the file is a dynamic object or not (if it is EXEC, it is
not dynamic, otherwise it needs to have vm_start taken off). I also
fixed the inline issue.

Warmest Regards,

Steve

P.S. I will also attach the patch in case the cut-and-paste below gets
mangled beyond recognition.

/\/\/\/\/\ Begin Patch /\/\/\/\/\
diff -aur a/kernel/cobalt/debug.c b/kernel/cobalt/debug.c
--- a/kernel/cobalt/debug.c 2019-01-14 10:11:19.000000000 -0500
+++ b/kernel/cobalt/debug.c 2019-03-21 17:07:23.466631608 -0400
@@ -123,6 +123,7 @@
  int depth;
  struct backtrace {
  unsigned long pc;
+ unsigned long vm_start;
  const char *mapname;
  } backtrace[SIGSHADOW_BACKTRACE_DEPTH];
  /* Program hash value of the caller. */
@@ -248,17 +249,8 @@
  if (vma == NULL)
  continue;

- /*
- * Hack. Unlike DSOs, executables and interpreters
- * (e.g. dynamic linkers) are protected against write
- * attempts. Use this to determine when $pc should be
- * fixed up by subtracting the mapping base address in
- * the DSO case.
- */
- if (!(vma->vm_flags & VM_DENYWRITE))
- pc -= vma->vm_start;
-
  spot.backtrace[depth].pc = pc;
+ spot.backtrace[depth].vm_start = vma->vm_start;

  /*
  * Even in case we can't fetch the map name, we still
@@ -448,8 +440,9 @@
         reason_str[p->spot.reason], p->spot.thread);

  for (n = 0; n < p->spot.depth; n++)
- xnvfile_printf(it, "0x%lx %s\n",
+ xnvfile_printf(it, "0x%lx 0x%lx %s\n",
         p->spot.backtrace[n].pc,
+        p->spot.backtrace[n].vm_start,
         p->spot.backtrace[n].mapname ?: "?");

  xnvfile_printf(it, ".\n");
diff -aur a/utils/slackspot/slackspot.c b/utils/slackspot/slackspot.c
--- a/utils/slackspot/slackspot.c 2019-01-11 08:40:38.000000000 -0500
+++ b/utils/slackspot/slackspot.c 2019-03-21 17:05:23.666130908 -0400
@@ -87,6 +87,7 @@

 struct location {
  unsigned long pc;
+ unsigned long vm_start;
  char *function;
  char *file;
  int lineno;
@@ -110,6 +111,7 @@
  int depth;
  struct backtrace {
  unsigned long pc;
+ unsigned long vm_start;
  struct mapping *mapping;
  const struct location *where;
  } backtrace[SIGSHADOW_BACKTRACE_DEPTH];
@@ -125,7 +127,7 @@
  return fnmatch(f->exp, p->thread_name, 0);
 }

-static int filter_pid(struct filter *f,  struct relax_spot *p)
+static int filter_pid(struct filter *f, struct relax_spot *p)
 {
  char pid[16];

@@ -336,7 +338,7 @@
 {
  struct relax_spot *p;
  struct mapping *m;
- unsigned long pc;
+ unsigned long pc, vm_start;
  char *mapping, c;
  ENTRY e, *ep;
  int ret;
@@ -375,8 +377,9 @@
  if (c == '.' && getc(fp) == '\n')
  break;
  ungetc(c, fp);
- ret = fscanf(fp, "%lx %m[^\n]\n", &pc, &mapping);
- if (ret != 2)
+ ret = fscanf(fp, "%lx %lx %m[^\n]\n",
+      &pc, &vm_start, &mapping);
+ if (ret != 3)
  goto bad_input;

  mapping = resolve_path(mapping);
@@ -405,6 +408,7 @@
  * usually works fine...
  */
  p->backtrace[p->depth].pc = pc - 1;
+ p->backtrace[p->depth].vm_start = vm_start;
  p->backtrace[p->depth].mapping = m;
  p->backtrace[p->depth].where = &undefined_location;
  p->depth++;
@@ -439,13 +443,15 @@

 static void resolve_spots(void)
 {
- char *a2l, *a2lcmd, *s, buf[BUFSIZ];
+ char *a2l, *a2lcmd, *relfcmd, *s, buf[BUFSIZ];
+ int ch;
  struct relax_spot *p;
  struct backtrace *b;
  struct location *l;
  struct mapping *m;
  struct stat sbuf;
- int ret, depth;
+ int ret, depth, use_offset;
+ unsigned long pc;
  FILE *fp;

  /*
@@ -472,6 +478,7 @@
  goto no_mem;

  l->pc = b->pc;
+ l->vm_start = b->vm_start;
  l->function = NULL;
  l->file = NULL;
  l->lineno = 0;
@@ -493,13 +500,25 @@
  if (ret || !S_ISREG(sbuf.st_mode))
  continue;

+ ret = asprintf(&relfcmd,
+        "%sreadelf -h %s | grep -q \"Type:\\s*DYN\"",
+        toolchain_prefix, m->name);
+ fp = popen(relfcmd, "r");
+ if (fp == NULL)
+ error(1, errno, "cannot run %s", relfcmd);
+
+ use_offset =  !pclose(fp);
+ free(relfcmd);
+
  ret = asprintf(&a2l,
-        "%saddr2line --demangle --inlines --functions --exe=%s",
+        "%saddr2line --addresses --demangle --inlines --functions --exe=%s",
         toolchain_prefix, m->name);
  if (ret < 0)
  goto no_mem;

  for (l = m->locs, s = a2l, a2lcmd = NULL; l; l = l->next) {
+ if (use_offset)
+ l->pc -= l->vm_start;
  ret = asprintf(&a2lcmd, "%s 0x%lx", s, l->pc);
  if (ret < 0)
  goto no_mem;
@@ -512,24 +531,36 @@
  error(1, errno, "cannot run %s", a2lcmd);

  for (l = m->locs; l; l = l->next) {
- ret = fscanf(fp, "%ms\n", &l->function);
+ ret = fscanf(fp, "%lx\n", &pc);
  if (ret != 1)
  goto bad_output;
  /*
- * Don't trust fscanf range specifier, we may
- * have colons in the pathname.
+ * Loop until we get a new address.
  */
- s = fgets(buf, sizeof(buf), fp);
- if (s == NULL)
- goto bad_output;
- s = strrchr(s, ':');
- if (s == NULL)
- continue;
- *s++ = '\0';
- if (strcmp(buf, "??")) {
- l->lineno = atoi(s);
- l->file = strdup(buf);
+ while ((ch = fgetc(fp)) != '0' && ch != EOF) {
+ ungetc(ch, fp);
+ ret = fscanf(fp, "%ms\n", &l->function);
+ if (ret != 1) {
+ goto bad_output;
+ }
+ /*
+ * Don't trust fscanf range specifier, we may
+ * have colons in the pathname.
+ */
+ s = fgets(buf, sizeof(buf), fp);
+ if (s == NULL)
+ goto bad_output;
+ s = strrchr(s, ':');
+ if (s == NULL)
+ continue;
+ *s++ = '\0';
+ if (strcmp(buf, "??")) {
+ l->lineno = atoi(s);
+ l->file = strdup(buf);
+ }
  }
+ if (ch == '0')
+ ungetc(ch, fp);
  }

  pclose(fp);

/\/\/\/\/\ End Patch /\/\/\/\/\
-------------- next part --------------
A non-text attachment was scrubbed...
Name: fix_slackspot.patch
Type: application/octet-stream
Size: 5293 bytes
Desc: not available
URL: <http://xenomai.org/pipermail/xenomai/attachments/20190321/541bd5d0/attachment.obj>

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: Still More Slackspot Issues - Patch Included
  2019-03-21 23:31   ` Still More Slackspot Issues - Patch Included Stephen D. Cohen
@ 2019-03-22 15:51     ` Philippe Gerum
  0 siblings, 0 replies; 19+ messages in thread
From: Philippe Gerum @ 2019-03-22 15:51 UTC (permalink / raw)
  To: Stephen D. Cohen, xenomai

On 3/22/19 12:31 AM, Stephen D. Cohen via Xenomai wrote:
> Folks,
> 
>      Some time back I submitted a patch for the slackspot issue
> regarding when to remove the vm_start offset from the program counter
> in the relax handling mechanism in debug.c. My solution had the
> unfortunate flaw that it peeked into the actual ELF section headers in
> the running system (ewww...) and was deemed unworthy. The solution
> that got implemented, using VM_DENYWRITE to detect dynamic objects,
> has the unfortunate flaw of not working with position independent
> executable programs. The very problem that got me started in the first
> place.
> 
>      As luck would have it, I recently needed slackspot to figure out
> some issues with our application. So I set out to make it work again.
> In the process, I also found another issue - when the target
> application uses inline routines, all the spots in the same file past
> the inlined routine are reported incorrectly. This is due to slackspot
> assuming a 1:1 mapping between addresses and reported results. The
> inlined routines actually report two sets of results for each address.
> 
>      So I propose the attached solution. Move the trouble of
> identifying the ELF object type out of the kernel and put it in
> slackspot instead. Just store both the pc and vm_start for every spot,
> then figure it all out in slackspot. Slackspot then uses elfread to
> determine if the file is a dynamic object or not (if it is EXEC, it is
> not dynamic, otherwise it needs to have vm_start taken off). I also
> fixed the inline issue.

Ack, moving the symbol resolution to user-space just makes sense.

-- 
Philippe.


^ permalink raw reply	[flat|nested] 19+ messages in thread

end of thread, other threads:[~2019-03-22 15:51 UTC | newest]

Thread overview: 19+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-03-21 17:13 [PATCH 00/16] multicast, VLAN support for RTnet Philippe Gerum
2019-03-21 17:13 ` [PATCH 01/16] net/stack: plan for merging private device flags with netdev_priv_flags Philippe Gerum
2019-03-21 17:13 ` [PATCH 02/16] net/stack: add multicast support Philippe Gerum
2019-03-21 17:13 ` [PATCH 03/16] utils/net: rtifconfig: display device name untruncated Philippe Gerum
2019-03-21 17:13 ` [PATCH 04/16] net/stack: add support for VLAN filtering Philippe Gerum
2019-03-21 17:13 ` [PATCH 05/16] utils/net: add VLAN filter configuration tool Philippe Gerum
2019-03-21 17:13 ` [PATCH 06/16] net/udp: allow retrieving irq timestamp with SIOCGSTAMP ioctl Philippe Gerum
2019-03-21 17:13 ` [PATCH 07/16] net/udp sendmsg: do not return an error if dest addr is null Philippe Gerum
2019-03-21 17:13 ` [PATCH 08/16] net/stack: rtskb: increase buffer size Philippe Gerum
2019-03-21 17:13 ` [PATCH 09/16] net/stack: manager: ratelimit printk when dropping buffers Philippe Gerum
2019-03-21 17:13 ` [PATCH 10/16] net/ipv4: icmp: forward unused packets to proxy Philippe Gerum
2019-03-21 17:13 ` [PATCH 11/16] net/drivers: e1000e: enable multicast Philippe Gerum
2019-03-21 17:13 ` [PATCH 12/16] net/drivers: e1000e: enable VLAN filtering Philippe Gerum
2019-03-21 17:13 ` [PATCH 13/16] net/drivers: e1000e: add netdevice stats Philippe Gerum
2019-03-21 17:13 ` [PATCH 14/16] net/drivers: igb: enable multicast Philippe Gerum
2019-03-21 17:13 ` [PATCH 15/16] net/drivers: igb: enable VLAN filtering Philippe Gerum
2019-03-21 17:13 ` [PATCH 16/16] demo/net: add rtnet tests Philippe Gerum
2019-03-21 23:31   ` Still More Slackspot Issues - Patch Included Stephen D. Cohen
2019-03-22 15:51     ` Philippe Gerum

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.