Hi,
here is the patch, I'm finalizing and testing a new version, available
soon...
Bruno.
el hedadi Amine a écrit :
Hi,
Im trying to test your multicast patch but I need the igmp.c file
witch is not present in the patch.
can you send me this file !
Amine
----- Message d'origine ----
De : Bruno Carlus <[EMAIL PROTECTED]>
À : [email protected]
Envoyé le : Lundi, 17 Mars 2008, 18h33mn 29s
Objet : [RTnet-developers] Multicast patch
Hi,
you can find herejoined an uptodate patch for multicast support working
with current revision 1155.
Please feel free to comment. The patch is based upon the old amine one.
I'm still working on it and testing it ...
Bruno.
__________________________________________________
Do You Yahoo!?
En finir avec le spam? Yahoo! Mail vous offre la meilleure protection
possible contre les messages non sollicités
http://mail.yahoo.fr Yahoo! Mail
Index: tools/rtifconfig.c
===================================================================
--- tools/rtifconfig.c (révision 1155)
+++ tools/rtifconfig.c (copie de travail)
@@ -105,10 +105,11 @@
}
flags = cmd.args.info.flags &
- (IFF_UP | IFF_BROADCAST | IFF_LOOPBACK | IFF_RUNNING | IFF_PROMISC);
+ (IFF_UP | IFF_BROADCAST | IFF_MULTICAST | IFF_LOOPBACK | IFF_RUNNING | IFF_PROMISC);
printf(" %s%s%s%s%s%s MTU: %d\n\n",
((flags & IFF_UP) != 0) ? "UP " : "",
((flags & IFF_BROADCAST) != 0) ? "BROADCAST " : "",
+ ((flags & IFF_MULTICAST) != 0) ? "MULTICAST " : "",
((flags & IFF_LOOPBACK) != 0) ? "LOOPBACK " : "",
((flags & IFF_RUNNING) != 0) ? "RUNNING " : "",
((flags & IFF_PROMISC) != 0) ? "PROMISC " : "",
Index: configure.ac
===================================================================
--- configure.ac (révision 1155)
+++ configure.ac (copie de travail)
@@ -1076,6 +1076,24 @@
dnl ======================================================================
+dnl multicast
+dnl ======================================================================
+
+AC_MSG_CHECKING([whether to build multicast])
+AC_ARG_ENABLE(multicast,
+AS_HELP_STRING([--enable-multicast], [build IP protocol multicast driver (legacy) @<:@default=no@:>@]),
+ [case "$enableval" in
+ y | yes) CONFIG_RTNET_MULTICAST=y ;;
+ *) CONFIG_RTNET_MULTICAST=n ;;
+ esac])
+AC_MSG_RESULT([${CONFIG_RTNET_MULTICAST:-n}])
+AM_CONDITIONAL(CONFIG_RTNET_MULTICAST,[test "$CONFIG_RTNET_MULTICAST" = "y"])
+if test "$CONFIG_RTNET_MULTICAST" = "y"; then
+ AC_DEFINE(CONFIG_RTNET_MULTICAST,1,[multicast support])
+fi
+
+
+dnl ======================================================================
dnl RTcfg
dnl ======================================================================
Index: stack/ipv4/Kconfig
===================================================================
--- stack/ipv4/Kconfig (révision 1155)
+++ stack/ipv4/Kconfig (copie de travail)
@@ -41,3 +41,10 @@
combination with CONFIG_RTNET_RTIPV4_NETROUTING.
See Documentation/README.routing for further information.
+
+config RTNET_MULTICAST
+ bool "Multicast"
+ depends on RTNET_RTIPV4
+ ---help---
+ Enables multicast basic support.
+
Index: stack/ipv4/GNUmakefile.am
===================================================================
--- stack/ipv4/GNUmakefile.am (révision 1155)
+++ stack/ipv4/GNUmakefile.am (copie de travail)
@@ -17,6 +17,7 @@
ip_sock.c \
udp.c \
icmp.c \
+ igmp.c \
ip_output.c \
ip_fragment.c
Index: stack/ipv4/af_inet.c
===================================================================
--- stack/ipv4/af_inet.c (révision 1155)
+++ stack/ipv4/af_inet.c (copie de travail)
@@ -31,6 +31,7 @@
#include <rtnet_rtpc.h>
#include <ipv4/arp.h>
#include <ipv4/icmp.h>
+#include <ipv4/igmp.h>
#include <ipv4/ip_output.h>
#include <ipv4/protocol.h>
#include <ipv4/route.h>
@@ -248,6 +249,12 @@
if (rtdev->flags & IFF_BROADCAST)
rt_ip_route_add_host(up_cmd->args.up.broadcast_ip,
rtdev->broadcast, rtdev);
+
+#ifdef CONFIG_RTNET_MULTICAST
+ if (!(rtdev->flags & IFF_LOOPBACK) && (rtdev->flags & IFF_MULTICAST))
+ rt_ip_mc_up(rtdev);
+#endif
+
}
}
@@ -256,6 +263,10 @@
static void rt_ip_ifdown(struct rtnet_device *rtdev)
{
rt_ip_route_del_all(rtdev);
+#ifdef CONFIG_RTNET_MULTICAST
+ if (!(rtdev->flags & IFF_LOOPBACK) && (rtdev->flags & IFF_MULTICAST))
+ rt_ip_mc_down(rtdev);
+#endif
}
@@ -327,6 +338,9 @@
rt_inet_protocols[i]=NULL;
rt_icmp_init();
+#ifdef CONFIG_RTNET_MULTICAST
+ rt_igmp_init();
+#endif
rt_udp_init();
#ifdef CONFIG_PROC_FS
@@ -360,6 +374,9 @@
#endif /* CONFIG_PROC_FS */
rt_udp_release();
+#ifdef CONFIG_RTNET_MULTICAST
+ rt_igmp_release();
+#endif
rt_icmp_release();
rt_arp_release();
rt_ip_release();
@@ -381,6 +398,9 @@
/* Transport-Layer */
rt_udp_release();
+#ifdef CONFIG_RTNET_MULTICAST
+ rt_igmp_release();
+#endif
rt_icmp_release();
/* Network-Layer */
Index: stack/ipv4/arp.c
===================================================================
--- stack/ipv4/arp.c (révision 1155)
+++ stack/ipv4/arp.c (copie de travail)
@@ -22,6 +22,8 @@
*/
#include <rtdev.h>
+#include <net/ip.h>
+#include <linux/if_arp.h>
#include <stack_mgr.h>
#include <ipv4/arp.h>
@@ -180,6 +182,38 @@
+#ifdef CONFIG_RTNET_MULTICAST
+/***
+ * rt_arp_mc_map: arp multicast mapping
+ */
+int rt_arp_mc_map(u32 addr, u8 *haddr, struct rtnet_device *dev, int dir)
+{
+ int ret = -EINVAL;
+
+ switch (dev->type) {
+ case ARPHRD_ETHER:
+ case ARPHRD_FDDI:
+ case ARPHRD_IEEE802:
+ ip_eth_mc_map(addr, haddr);
+ ret = 0;
+ break;
+ case ARPHRD_IEEE802_TR:
+ ip_tr_mc_map(addr, haddr);
+ ret = 0;
+ break;
+ default:
+ if (dir) {
+ memcpy(haddr, dev->broadcast, dev->addr_len);
+ ret = 0;
+ break;
+ }
+ }
+ return ret;
+}
+#endif
+
+
+
static struct rtpacket_type arp_packet_type = {
type: __constant_htons(ETH_P_ARP),
handler: &rt_arp_rcv
Index: stack/ipv4/ip_sock.c
===================================================================
--- stack/ipv4/ip_sock.c (révision 1155)
+++ stack/ipv4/ip_sock.c (copie de travail)
@@ -26,8 +26,8 @@
#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)
{
@@ -44,6 +44,28 @@
case IP_TOS:
s->prot.inet.tos = *(unsigned int *)optval;
break;
+#ifdef CONFIG_RTNET_MULTICAST
+ case RT_IP_ADD_MEMBERSHIP:
+ case RT_IP_DROP_MEMBERSHIP:
+ {
+ struct ip_mreq *mreq = (struct ip_mreq*)optval;
+ if (optname == RT_IP_ADD_MEMBERSHIP) {
+ err = rt_ip_mc_join_group(s,mreq);
+ }
+ else
+ err = rt_ip_mc_leave_group(s,mreq);
+ break;
+ }
+ case IP_MULTICAST_IF:
+ rtdm_printk("Option IP_MULTICAST_IF not implemented.\n");
+ break;
+ case IP_MULTICAST_TTL:
+ rtdm_printk("Option IP_MULTICAST_TTL not implemented.\n");
+ break;
+ case IP_MULTICAST_LOOP:
+ rtdm_printk("Option IP_MULTICAST_LOOP not implemented.\n");
+ break;
+#endif
default:
err = -ENOPROTOOPT;
Index: stack/ipv4/ip_output.c
===================================================================
--- stack/ipv4/ip_output.c (révision 1155)
+++ stack/ipv4/ip_output.c (copie de travail)
@@ -113,7 +113,11 @@
iph->tot_len = htons(fraglen);
iph->id = htons(msg_rt_ip_id);
iph->frag_off = htons(frag_off);
- iph->ttl = 255;
+
+ if (MULTICAST(rt->ip))
+ iph->ttl = 1;
+ else iph->ttl = 255;
+
iph->protocol = sk->protocol;
iph->saddr = rtdev->local_ip;
iph->daddr = rt->ip;
@@ -216,7 +220,11 @@
iph->tot_len = htons(length);
iph->id = htons(msg_rt_ip_id);
iph->frag_off = htons(IP_DF);
- iph->ttl = 255;
+
+ if(MULTICAST(rt->ip))
+ iph->ttl = 1;
+ else iph->ttl = 255;
+
iph->protocol = sk->protocol;
iph->saddr = rtdev->local_ip;
iph->daddr = rt->ip;
Index: stack/ipv4/udp.c
===================================================================
--- stack/ipv4/udp.c (révision 1155)
+++ stack/ipv4/udp.c (copie de travail)
@@ -37,6 +37,7 @@
#include <ipv4/ip_fragment.h>
#include <ipv4/ip_output.h>
#include <ipv4/ip_sock.h>
+#include <ipv4/arp.h>
#include <ipv4/protocol.h>
#include <ipv4/route.h>
#include <ipv4/udp.h>
@@ -535,6 +536,7 @@
int err;
rtdm_lockctx_t context;
+ char buf[MAX_ADDR_LEN];
if ((len < 0) || (len > 0xFFFF-sizeof(struct iphdr)-sizeof(struct udphdr)))
return -EMSGSIZE;
@@ -572,11 +574,37 @@
if ((daddr | dport) == 0)
return -EINVAL;
- /* get output route */
- err = rt_ip_route_output(&rt, daddr, saddr);
- if (err)
- return err;
+ /* if daddr is a multicast @ we try to map it */
+ if (MULTICAST(daddr)) {
+ if (saddr != INADDR_ANY) {
+ rt.rtdev = (struct rtnet_device*)rt_ip_dev_find(saddr);
+ if (rt.rtdev) {
+ if (rt_arp_mc_map(daddr, buf,rt.rtdev, 0) == 0) {
+ memcpy(rt.dev_addr,buf,sizeof(buf));
+ rt.ip=daddr;
+ }
+ else {
+ // Can't map multicast adress
+ return -EHOSTUNREACH;
+ }
+ }
+ else {
+ //Can't locate rtdev
+ return -EHOSTUNREACH;
+ }
+ }
+ else
+ return -EHOSTUNREACH;
+ }
+ /* if daddr is not a multicast @ we use routing */
+ else {
+ /* get output route */
+ err = rt_ip_route_output(&rt, daddr, saddr);
+ if (err)
+ return err;
+ }
+
/* check if specified source address fits */
if ((saddr != INADDR_ANY) && (saddr != rt.rtdev->local_ip)) {
rtdev_dereference(rt.rtdev);
@@ -709,8 +737,8 @@
if (skb->ip_summed != CHECKSUM_UNNECESSARY)
skb->csum = csum_tcpudp_nofold(saddr, daddr, ulen, IPPROTO_UDP, 0);
- /* patch broadcast daddr */
- if (daddr == rtdev->broadcast_ip)
+ /* patch broadcast / multicast daddr */
+ if ((daddr == rtdev->broadcast_ip) || (MULTICAST(daddr)))
daddr = rtdev->local_ip;
/* find the destination socket */
Index: stack/ipv4/igmp.c
===================================================================
--- stack/ipv4/igmp.c (révision 0)
+++ stack/ipv4/igmp.c (révision 0)
@@ -0,0 +1,732 @@
+/*
+ * Linux NET3: Internet Group Management Protocol [IGMP]
+ *
+ * This code implements the IGMP protocol as defined in RFC1112. There has
+ * been a further revision of this protocol since which is now supported.
+ *
+ * If you have trouble with this module be careful what gcc you have used,
+ * the older version didn't come out right using gcc 2.5.8, the newer one
+ * seems to fall out with gcc 2.6.2.
+ *
+ * Version: $Id: igmp.c,v 1.46 2001/07/27 09:27:29 davem Exp $
+ *
+ * Authors:
+ * Alan Cox <[EMAIL PROTECTED]>
+ *
+ * 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: [EMAIL PROTECTED] and [EMAIL PROTECTED]
+ * 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 <linux/in.h>
+#include <rtnet_socket.h>
+#include <rtdev.h>
+#include <rtdm/rtdm_driver.h>
+#include <ipv4/protocol.h>
+#include <ipv4/route.h>
+#include <ipv4/arp.h>
+
+#ifdef CONFIG_RTNET_MULTICAST
+
+#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)
+#ifdef CONFIG_IP_MULTICAST
+
+/* Parameter names and values are taken from igmp-v2-06 draft */
+
+#define IGMP_V1_Router_Present_Timeout (400*HZ)
+#define IGMP_Unsolicited_Report_Interval (10*HZ)
+#define IGMP_Query_Response_Interval (10*HZ)
+#define IGMP_Unsolicited_Report_Count 2
+
+
+#define IGMP_Initial_Report_Delay (1)
+
+/* IGMP_Initial_Report_Delay is not from IGMP specs!
+ * IGMP specs require to report membership immediately after
+ * joining a group, but we delay the first report by a
+ * small interval. It seems more natural and still does not
+ * contradict to specs provided this delay is small enough.
+ */
+
+#define IGMP_V1_SEEN(in_dev) ((in_dev)->mr_v1_seen && (long)(jiffies - (in_dev)->mr_v1_seen) < 0)
+
+#endif
+/***
+ * 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 ip_mc_list *mc_list;
+static rtdm_lock_t mc_list_lock;
+rtdm_task_t rt_task;
+
+/*
+ * Send an IGMP report.
+ */
+
+#define IGMP_SIZE (sizeof(struct igmphdr)+sizeof(struct iphdr)+4)
+
+/* Don't just hand NF_HOOK skb->dst->output, in case netfilter hook
+ changes route */
+/*
+static inline int
+output_maybe_reroute(struct sk_buff *skb)
+{
+ return skb->dst->output(skb);
+}
+*/
+
+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) {
+ rtdm_printk("can't alloc rtskb \n");
+ return -1;
+ }
+
+ skb->rtdev = rtdev;
+ skb->priority = RT_IGMP_SKB_PRIO;
+ rtskb_reserve(skb, (rtdev->hard_header_len+15)&~15);
+ skb->nh.iph = iph = (struct iphdr *) rtskb_put(skb, sizeof(struct iphdr)+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)
+ goto error;
+ }
+
+ err = rtdev_xmit(skb);
+ if (err)
+ return -EAGAIN;
+ else
+ return 0;
+error:
+ kfree_rtskb(skb);
+ return -1;
+}
+
+
+
+static void igmp_heard_query(struct rtnet_device *rtdev, unsigned char max_resp_time,
+ u32 group)
+{
+ struct ip_mc_list *im;
+ int max_delay;
+ rtdm_lockctx_t context;
+
+ max_delay = max_resp_time*(HZ/IGMP_TIMER_SCALE);
+ //rtdm_printk("max delay %d \n ",max_delay);
+
+ rtdm_lock_get_irqsave(&mc_list_lock, context);
+ for (im=mc_list; im!=NULL; im=im->next) {
+ if (im->multiaddr != IGMP_ALL_HOSTS) {
+ if (group && im->multiaddr == group) {
+ im->loaded=0;
+ break;
+ }
+ else
+ im->loaded=0;
+ }
+ }
+ rtdm_lock_put_irqrestore(&mc_list_lock, context);
+}
+
+
+
+int 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)) {
+ kfree_rtskb(skb);
+ return -EINVAL;
+ }
+
+ switch (ih->type) {
+ case IGMP_HOST_MEMBERSHIP_QUERY:
+ igmp_heard_query(rtdev, ih->code, ih->group);
+ break;
+ case IGMP_HOST_MEMBERSHIP_REPORT:
+ case IGMP_HOST_NEW_MEMBERSHIP_REPORT:
+ 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);
+ }
+ kfree_rtskb(skb);
+ return 0;
+}
+
+
+
+/***
+ * rt_ip_mc_filter_add - Add a filter to a device
+ */
+static void rt_ip_mc_filter_add(struct rtnet_device *rtdev, u32 addr)
+{
+ char buf[MAX_ADDR_LEN];
+ struct rtnet_device *dev = rtdev;
+
+ /* 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, dev, 0) == 0)
+ rtdev_mc_add(dev,buf,dev->addr_len,0);
+}
+
+
+
+/***
+ * rt_ip_mc_filter_del - 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)
+ rtdev_mc_delete(dev,buf,dev->addr_len,0);
+}
+
+
+
+/***
+ * igmp_group_dropped
+ */
+static void igmp_group_dropped(struct ip_mc_list *im)
+{
+ if (im->loaded) {
+ rt_ip_mc_filter_del((struct rtnet_device*)im->interface, im->multiaddr);
+ }
+}
+
+
+
+/***
+ * igmp_group_added
+ */
+static void igmp_group_added(struct ip_mc_list *im)
+{
+ rt_ip_mc_filter_add((struct rtnet_device*)im->interface, im->multiaddr);
+}
+
+
+
+/***
+ * Multicast list managers
+ */
+
+
+
+/***
+ * rt_ip_mc_inc_group - A socket has joined a multicast group on device dev.
+ */
+void rt_ip_mc_inc_group(struct rtnet_device *rtdev, u32 addr)
+{
+ struct ip_mc_list *im;
+ rtdm_lockctx_t context;
+
+ rtdm_lock_get_irqsave(&mc_list_lock, context);
+ for (im=mc_list; im; im=im->next) {
+ if (im->multiaddr == addr) {
+ im->users++;
+ goto out;
+ }
+ }
+
+ im = (struct ip_mc_list *)kmalloc(sizeof(*im), GFP_KERNEL);
+ if (!im)
+ goto out;
+ im->users=1;
+ //(struct rtnet_devcie*)
+ im->interface=rtdev;
+ im->multiaddr=addr;
+ im->loaded = 0;
+ im->next=mc_list;
+ mc_list=im;
+
+ igmp_group_added(im);
+out:
+ rtdm_lock_put_irqrestore(&mc_list_lock, context);
+ return;
+}
+
+
+
+/***
+ * rt_ip_mc_dec_group - A socket has left a multicast group on device dev
+ */
+void rt_ip_mc_dec_group(struct rtnet_device *rtdev, u32 addr)
+{
+ struct ip_mc_list *i, **ip;
+ rtdm_lockctx_t context;
+
+ rtdm_lock_get_irqsave(&mc_list_lock, context);
+ for (ip=&mc_list; (i=*ip)!=NULL; ip=&i->next) {
+ if (i->multiaddr==addr) {
+ if (--i->users == 0) {
+ *ip = i->next;
+ igmp_group_dropped(i);
+ rtdm_lock_put_irqrestore(&mc_list_lock, context);
+ return;
+ }
+ break;
+ }
+ }
+ rtdm_lock_put_irqrestore(&mc_list_lock, context);
+}
+
+
+
+/***
+ * rt_ip_mc_down - Device going down
+ */
+void rt_ip_mc_down(struct rtnet_device *rtdev)
+{
+ struct ip_mc_list *i;
+
+ for (i=mc_list; i; i=i->next)
+ igmp_group_dropped(i);
+
+ rt_ip_mc_dec_group(rtdev, IGMP_ALL_HOSTS);
+}
+
+
+
+/***
+ * rt_ip_mc_up - Device going up
+ */
+void rt_ip_mc_up(struct rtnet_device *rtdev)
+{
+ struct ip_mc_list *i;
+
+ rt_ip_mc_inc_group(rtdev, IGMP_ALL_HOSTS);
+ for (i=mc_list; i; i=i->next)
+ igmp_group_added(i);
+}
+
+
+
+/***
+ * ip_mc_destroy_dev - Device is about to be destroyed: clean up.
+ */
+/*
+void ip_mc_destroy_dev(struct in_device *in_dev)
+{
+ struct ip_mc_list *i;
+
+ ASSERT_RTNL();
+
+ write_lock_bh(&in_dev->lock);
+ while ((i = in_dev->mc_list) != NULL) {
+ in_dev->mc_list = i->next;
+ write_unlock_bh(&in_dev->lock);
+
+ igmp_group_dropped(i);
+ ip_ma_put(i);
+
+ write_lock_bh(&in_dev->lock);
+ }
+ write_unlock_bh(&in_dev->lock);
+}
+*/
+
+
+
+/***
+ * rt_ip_mc_find_dev
+ */
+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);
+ if (!rtdev)
+ return NULL;
+ }
+
+ return rtdev;
+}
+
+
+
+/***
+ * rt_ip_mc_join_group - Join a socket to a group
+ */
+int sysctl_igmp_max_memberships = IP_MAX_MEMBERSHIPS;
+
+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);
+
+ if (!rtdev) {
+ return -ENODEV;
+ }
+
+ if (!MULTICAST(addr)) {
+ return -EINVAL;
+ }
+ rt_ip_mc_inc_group(rtdev, addr);
+
+ return err;
+}
+
+
+
+/***
+ * rt_ip_mc_leave_group - 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);
+ if (!rtdev) {
+ return -ENODEV;
+ }
+ rt_igmp_send_report(rtdev, addr, IGMP_HOST_LEAVE_MESSAGE);
+ rt_ip_mc_dec_group(rtdev, addr);
+ return 0;
+}
+
+
+
+/***
+ * ip_mc_drop_socket - A socket is closing.
+ */
+/*
+void ip_mc_drop_socket(struct sock *sk)
+{
+ struct ip_mc_socklist *iml;
+
+ if (sk->protinfo.af_inet.mc_list == NULL)
+ return;
+
+ rtnl_lock();
+ while ((iml=sk->protinfo.af_inet.mc_list) != NULL) {
+ struct in_device *in_dev;
+ sk->protinfo.af_inet.mc_list = iml->next;
+
+ if ((in_dev = inetdev_by_index(iml->multi.imr_ifindex)) != NULL) {
+ ip_mc_dec_group(in_dev, iml->multi.imr_multiaddr.s_addr);
+ in_dev_put(in_dev);
+ }
+ sock_kfree_s(sk, iml, sizeof(*iml));
+
+ }
+ rtnl_unlock();
+}
+*/
+
+
+
+/***
+ * ip_check_mc
+ */
+/*
+int ip_check_mc(struct in_device *in_dev, u32 mc_addr)
+{
+ struct ip_mc_list *im;
+
+ read_lock(&in_dev->lock);
+ for (im=in_dev->mc_list; im; im=im->next) {
+ if (im->multiaddr == mc_addr) {
+ read_unlock(&in_dev->lock);
+ return 1;
+ }
+ }
+ read_unlock(&in_dev->lock);
+ return 0;
+}
+*/
+
+
+
+/***
+ * ip_mc_procinfo
+ */
+/*
+int ip_mc_procinfo(char *buffer, char **start, off_t offset, int length)
+{
+ off_t pos=0, begin=0;
+ struct ip_mc_list *im;
+ int len=0;
+ struct net_device *dev;
+
+ len=sprintf(buffer,"Idx\tDevice : Count Querier\tGroup Users Timer\tReporter\n");
+
+ read_lock(&dev_base_lock);
+ for(dev = dev_base; dev; dev = dev->next) {
+ struct in_device *in_dev = in_dev_get(dev);
+ char *querier = "NONE";
+
+ if (in_dev == NULL)
+ continue;
+
+ querier = IGMP_V1_SEEN(in_dev) ? "V1" : "V2";
+
+ len += sprintf(buffer+len,"%d\t%-10s: %5d %7s\n",
+ dev->ifindex, dev->name, dev->mc_count, querier);
+
+ read_lock(&in_dev->lock);
+ for (im = in_dev->mc_list; im; im = im->next) {
+ len += sprintf(buffer+len,
+ "\t\t\t\t%08lX %5d %d:%08lX\t\t%d\n",
+ im->multiaddr, im->users,
+ im->tm_running, im->timer.expires-jiffies, im->reporter);
+
+ pos = begin+len;
+ if (pos<offset) {
+ len = 0;
+ begin = pos;
+ }
+ if (pos>offset+length) {
+ read_unlock(&in_dev->lock);
+ in_dev_put(in_dev);
+ goto done;
+ }
+ }
+ read_unlock(&in_dev->lock);
+ in_dev_put(in_dev);
+ }
+done:
+ read_unlock(&dev_base_lock);
+
+ *start = buffer+(offset-begin);
+ len -= (offset-begin);
+ if (len>length)
+ len = length;
+ if (len<0)
+ len = 0;
+ return len;
+}
+*/
+
+
+/***
+ *
+ */
+void process(void *arg)
+{
+ struct ip_mc_list *im;
+ rtdm_lockctx_t context;
+
+ while(1){
+ rtdm_lock_get_irqsave(&mc_list_lock, context);
+ for (im=mc_list; im; im=im->next) {
+ if (im->loaded == 0) {
+ if (im->multiaddr != IGMP_ALL_HOSTS) {
+ rt_igmp_send_report((struct rtnet_device *)im->interface,im->multiaddr,IGMP_HOST_NEW_MEMBERSHIP_REPORT);
+ im->loaded = 1;
+ }
+ }
+ }
+ rtdm_lock_put_irqrestore(&mc_list_lock, context);
+ rtdm_task_wait_period();
+ }
+}
+
+
+
+/***
+ * rt_igmp_socket
+ */
+int rt_igmp_socket(struct rtdm_dev_context *context, int call_flags)
+{
+ /* we don't support user-created ICMP sockets */
+ return -ENOPROTOOPT;
+}
+
+
+
+/***
+ * rt_igmp_dest_socket
+ */
+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;
+}
+
+
+
+/***
+ * rt_icmp_rcv_err
+ */
+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
+};
+
+
+
+/***
+ * rt_igmp_init
+ */
+void __init rt_igmp_init(void)
+{
+ unsigned int skbs;
+ nanosecs_rel_t igmp_period;
+
+ igmp_socket.protocol = IPPROTO_IGMP;
+ igmp_socket.prot.inet.tos = 0;
+ igmp_socket.priority = 0;
+ rtdm_lock_init(&mc_list_lock);
+ /* create the rtskb pool */
+ skbs = rtskb_pool_init(&igmp_socket.skb_pool, IGMP_REPLY_POOL_SIZE);
+ if (skbs < IGMP_REPLY_POOL_SIZE)
+ rtdm_printk("RTnet: allocated only %d igmp rtskbs\n", skbs);
+
+ rt_inet_add_protocol(&igmp_protocol);
+ igmp_period = 50000000; /* 50 ms */
+ rtdm_task_init(&rt_task, "IGMP", (void *)process, 0, 0x3fffFfff, igmp_period);
+}
+
+
+
+/***
+ * rt_igmp_release
+ */
+void rt_igmp_release(void)
+{
+ rt_inet_del_protocol(&igmp_protocol);
+ rtdm_task_destroy(&rt_task);
+ rtskb_pool_release(&igmp_socket.skb_pool);
+}
+
+
+
+EXPORT_SYMBOL(rt_ip_mc_down);
+EXPORT_SYMBOL(rt_ip_mc_up);
+EXPORT_SYMBOL(rt_ip_mc_join_group);
+EXPORT_SYMBOL(rt_ip_mc_leave_group);
+
+#endif
Index: stack/rtnet_module.c
===================================================================
--- stack/rtnet_module.c (révision 1155)
+++ stack/rtnet_module.c (copie de travail)
@@ -72,10 +72,11 @@
for (i = 1; i <= MAX_RT_DEVICES; i++) {
rtdev = rtdev_get_by_index(i);
if (rtdev != NULL) {
- res = RTNET_PROC_PRINT("%d\t%-15s %s%s%s%s\n",
+ res = RTNET_PROC_PRINT("%d\t%-15s %s%s%s%s%s\n",
rtdev->ifindex, rtdev->name,
(rtdev->flags & IFF_UP) ? "UP" : "DOWN",
(rtdev->flags & IFF_BROADCAST) ? " BROADCAST" : "",
+ (rtdev->flags & IFF_MULTICAST) ? " MULTICAST" : "",
(rtdev->flags & IFF_LOOPBACK) ? " LOOPBACK" : "",
(rtdev->flags & IFF_PROMISC) ? " PROMISC" : "");
rtdev_dereference(rtdev);
Index: stack/include/ipv4/igmp.h
===================================================================
--- stack/include/ipv4/igmp.h (révision 0)
+++ stack/include/ipv4/igmp.h (révision 0)
@@ -0,0 +1,130 @@
+/*
+ * Linux NET3: Internet Group Management Protocol [IGMP]
+ *
+ * Authors:
+ * Alan Cox <[EMAIL PROTECTED]>
+ *
+ * Extended to talk the BSD extended IGMP protocol of mrouted 3.6
+ *
+ *
+ * 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 _LINUX_IGMP_H
+#define _LINUX_IGMP_H
+#include <asm/byteorder.h>
+#include <linux/init.h>
+#include <linux/in.h>
+#include <rtnet_socket.h>
+
+/*
+ * IGMP protocol structures
+ */
+
+/*
+ * Header in on cable format
+ */
+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
+
+
+/*
+ * Use the BSD names for these for compatibility
+ */
+
+#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)
+
+/*
+ * struct for keeping the multicast list in
+ */
+
+
+
+/* ip_mc_socklist is real list now. Speed is not argument;
+ this list never used in fast path code
+ */
+/*
+struct ip_mc_socklist
+{
+ struct ip_mc_socklist *next;
+ int count;
+ struct ip_mreqn multi;
+};
+*/
+
+struct ip_mc_list
+{
+ struct rtnet_device *interface;
+ unsigned long multiaddr;
+ struct ip_mc_list *next;
+// struct timer_list timer;
+ int users;
+// atomic_t refcnt;
+// spinlock_t lock;
+ char tm_running;
+ char reporter;
+ char unsolicit_count;
+ char loaded;
+};
+
+
+#ifdef __KERNEL__
+/*
+int ip_check_mc(struct in_device *dev, u32 mc_addr);
+int rt_igmp_rcv(struct sk_buff *);
+*/
+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 ip_mc_drop_socket(struct sock *sk);
+//void ip_mr_init(void);
+//void ip_mc_init_dev(struct in_device *);
+//void ip_mc_destroy_dev(struct in_device *);
+void rt_ip_mc_up(struct rtnet_device *);
+void rt_ip_mc_down(struct rtnet_device *);
+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 __init rt_igmp_init(void);
+void rt_igmp_release(void);
+#endif
+#endif
+
Index: stack/include/ipv4/arp.h
===================================================================
--- stack/include/ipv4/arp.h (révision 1155)
+++ stack/include/ipv4/arp.h (copie de travail)
@@ -50,5 +50,8 @@
void __init rt_arp_init(void);
void rt_arp_release(void);
+#ifdef CONFIG_RTNET_MULTICAST
+int rt_arp_mc_map(u32 addr, u8 *haddr, struct rtnet_device *dev, int dir);
+#endif
#endif /* __RTNET_ARP_H_ */
Index: stack/include/rtnet.h
===================================================================
--- stack/include/rtnet.h (révision 1155)
+++ stack/include/rtnet.h (copie de travail)
@@ -70,6 +70,10 @@
#define RTNET_RTIOC_EXTPOOL _IOW(RTIOC_TYPE_NETWORK, 0x14, unsigned int)
#define RTNET_RTIOC_SHRPOOL _IOW(RTIOC_TYPE_NETWORK, 0x15, unsigned int)
+/* ioctl for multicast */
+#define RT_IP_ADD_MEMBERSHIP _IOW(RTIOC_TYPE_NETWORK, 0x35, unsigned int)
+#define RT_IP_DROP_MEMBERSHIP _IOW(RTIOC_TYPE_NETWORK, 0x36, unsigned int)
+
/* socket transmission priorities */
#define SOCK_MAX_PRIO 0
#define SOCK_DEF_PRIO SOCK_MAX_PRIO + \
Index: stack/include/GNUmakefile.am
===================================================================
--- stack/include/GNUmakefile.am (révision 1155)
+++ stack/include/GNUmakefile.am (copie de travail)
@@ -31,6 +31,7 @@
ipv4/af_inet.h \
ipv4/arp.h \
ipv4/icmp.h \
+ ipv4/igmp.h \
ipv4/ip_fragment.h \
ipv4/ip_input.h \
ipv4/ip_output.h \
Index: stack/include/rtdev.h
===================================================================
--- stack/include/rtdev.h (révision 1155)
+++ stack/include/rtdev.h (copie de travail)
@@ -141,6 +141,10 @@
int (*do_ioctl)(struct rtnet_device *rtdev,
unsigned int request, void * cmd);
+
+ /* Added for multicast support */
+ void (*set_multicast_list) (struct rtnet_device *rtdev);
+
};
@@ -183,6 +187,15 @@
int rtdev_xmit_proxy(struct rtskb *skb);
#endif
+/* Functions used for multicast support */
+#ifdef CONFIG_RTNET_MULTICAST
+struct rtnet_device *rt_ip_dev_find(u32 addr);
+void rtdev_mc_upload(struct rtnet_device *dev);
+int rtdev_mc_delete(struct rtnet_device *dev, void *addr, int alen, int all);
+int rtdev_mc_add(struct rtnet_device *dev, void *addr, int alen, int newonly);
+void rtdev_set_allmulti(struct rtnet_device *dev, int inc);
+#endif
+
unsigned int rt_hard_mtu(struct rtnet_device *rtdev, unsigned int priority);
int rtdev_open(struct rtnet_device *rtdev);
Index: stack/include/rtskb.h
===================================================================
--- stack/include/rtskb.h (révision 1155)
+++ stack/include/rtskb.h (copie de travail)
@@ -183,6 +183,7 @@
struct tcphdr *th;
struct udphdr *uh;
struct icmphdr *icmph;
+ struct igmphdr *igmph; /* igmp header for multicast support */
struct iphdr *ipihdr;
unsigned char *raw;
} h;
Index: stack/rtdev.c
===================================================================
--- stack/rtdev.c (révision 1155)
+++ stack/rtdev.c (copie de travail)
@@ -306,7 +306,10 @@
rtdev->hard_header_len = ETH_HLEN;
rtdev->mtu = 1500; /* eth_mtu */
rtdev->addr_len = ETH_ALEN;
- rtdev->flags = IFF_BROADCAST; /* TODO: IFF_MULTICAST; */
+ rtdev->flags = IFF_BROADCAST;
+#ifdef CONFIG_MULTICAST_SUPPORT
+ rtdev->flags |= IFF_MULTICAST;
+#endif
rtdev->get_mtu = rt_hard_mtu;
memset(rtdev->broadcast, 0xFF, ETH_ALEN);
@@ -499,8 +502,8 @@
if ( !ret ) {
rtdev->flags |= (IFF_UP | IFF_RUNNING);
set_bit(__LINK_STATE_START, &rtdev->state);
-#if 0
- dev_mc_upload(dev); /* Initialize multicasting status */
+#ifdef CONFIG_RTNET_MULTICAST
+ rtdev_mc_upload(rtdev); /* Initialize multicasting status */
#endif
}
@@ -616,6 +619,212 @@
}
+
+#ifdef CONFIG_RTNET_MULTICAST
+/***
+ * __rt_ip_dev_find - 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;
+ rtdm_lockctx_t context;
+
+
+ rtdm_lock_get_irqsave(&rtnet_devices_rt_lock, context);
+
+ rtdev = __rt_ip_dev_find(addr);
+/* if (rtdev != NULL)
+ atomic_inc(&rtdev->refcount);
+*/
+ rtdm_lock_put_irqrestore(&rtnet_devices_rt_lock, context);
+
+ return rtdev;
+}
+
+
+
+/***
+ * __rtdev_mc_upload - Update the multicast list into the physical NIC controller.
+ */
+static void __rtdev_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(" Driver for %s not support multicast\n", dev->name);
+ return;
+ }
+ dev->set_multicast_list(dev);
+}
+
+
+
+/***
+ * __rtdev_mc_upload - Update the multicast list into the physical NIC controller.
+ */
+void rtdev_mc_upload(struct rtnet_device *dev)
+{
+ rtdm_mutex_lock(&dev->xmit_mutex);
+ __rtdev_mc_upload(dev);
+ rtdm_mutex_unlock(&dev->xmit_mutex);
+}
+
+/***
+ * rtdev_mc_delete - Delete a device level multicast
+ */
+int rtdev_mc_delete(struct rtnet_device *dev, void *addr, int alen, int glbl)
+{
+ int err = 0;
+ struct dev_mc_list *dmi, **dmip;
+
+ rtdm_mutex_lock(&dev->xmit_mutex);
+
+ 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--;
+
+ kfree(dmi);
+
+ /*
+ * We have altered the list, so the card
+ * loaded filter is now wrong. Fix it
+ */
+ __rtdev_mc_upload(dev);
+
+ rtdm_mutex_unlock(&dev->xmit_mutex);
+ return 0;
+ }
+ }
+ err = -ENOENT;
+done:
+ rtdm_mutex_unlock(&dev->xmit_mutex);
+ return err;
+}
+
+
+
+/***
+ * rtdev_mc_add - Add a device level multicast
+ */
+int rtdev_mc_add(struct rtnet_device *dev, void *addr, int alen, int glbl)
+{
+ int err = 0;
+ struct dev_mc_list *dmi, *dmi1;
+
+ dmi1 = (struct dev_mc_list *)kmalloc(sizeof(*dmi), GFP_ATOMIC);
+
+ rtdm_mutex_lock(&dev->xmit_mutex);
+ 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_mutex_unlock(&dev->xmit_mutex);
+ 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++;
+
+ __rtdev_mc_upload(dev);
+
+ rtdm_mutex_unlock(&dev->xmit_mutex);
+ return 0;
+
+done:
+ rtdm_mutex_unlock(&dev->xmit_mutex);
+ if (dmi1)
+ kfree(dmi1);
+ return err;
+}
+
+
+
+/***
+ * rtdev_mc_discard - Discard multicast list when a device is downed
+ */
+void rtdev_mc_discard(struct rtnet_device *dev)
+{
+ rtdm_mutex_lock(&dev->xmit_mutex);
+
+ while (dev->mc_list != NULL) {
+ struct dev_mc_list *tmp = dev->mc_list;
+ dev->mc_list = tmp->next;
+ if (tmp->dmi_users > tmp->dmi_gusers)
+ rtdm_printk("dev_mc_discard: multicast leakage! dmi_users=%d\n", tmp->dmi_users);
+ kfree(tmp);
+ }
+ dev->mc_count = 0;
+
+ rtdm_mutex_lock(&dev->xmit_mutex);
+}
+#endif
+
+
+
EXPORT_SYMBOL(rt_alloc_etherdev);
EXPORT_SYMBOL(rtdev_free);
@@ -638,4 +847,10 @@
EXPORT_SYMBOL(rtdev_xmit_proxy);
#endif
+#ifdef CONFIG_RTNET_MULTICAST
+EXPORT_SYMBOL(rtdev_mc_add);
+EXPORT_SYMBOL(rtdev_mc_delete);
+EXPORT_SYMBOL(rt_ip_dev_find);
+#endif
+
EXPORT_SYMBOL(rt_hard_mtu);
Index: drivers/e1000/e1000_main.c
===================================================================
--- drivers/e1000/e1000_main.c (révision 1155)
+++ drivers/e1000/e1000_main.c (copie de travail)
@@ -771,7 +771,9 @@
netdev->stop = &e1000_close;
netdev->hard_start_xmit = &e1000_xmit_frame;
// netdev->get_stats = &e1000_get_stats;
- // netdev->set_multicast_list = &e1000_set_multi;
+#ifdef CONFIG_RTNET_MULTICAST
+ netdev->set_multicast_list = &e1000_set_multi;
+#endif
// netdev->set_mac_address = &e1000_set_mac;
// netdev->change_mtu = &e1000_change_mtu;
// netdev->do_ioctl = &e1000_ioctl;
-------------------------------------------------------------------------
This SF.net email is sponsored by the 2008 JavaOne(SM) Conference
Don't miss this year's exciting event. There's still time to save $100.
Use priority code J8TL2D2.
http://ad.doubleclick.net/clk;198757673;13503038;p?http://java.sun.com/javaone
_______________________________________________
RTnet-developers mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/rtnet-developers