diff -urNb aodv-uu-0.7.2/Makefile maodv-umd-0.7.2/Makefile
--- aodv-uu-0.7.2/Makefile	Mon Jun  2 19:46:08 2003
+++ maodv-umd-0.7.2/Makefile	Fri Dec  5 17:43:09 2003
@@ -4,7 +4,10 @@
 SRC =	main.c list.c debug.c timer_queue.c aodv_socket.c aodv_hello.c \
 	aodv_neighbor.c aodv_timeout.c routing_table.c seek_list.c \
 	k_route.c aodv_rreq.c aodv_rrep.c aodv_rerr.c packet_input.c \
-	packet_queue.c libipq.c icmp.c
+	packet_queue.c libipq.c icmp.c maodv_grph.c maodv_mact.c \
+	multicast_routing_table.c igmp.c \
+	maodv_rreq.c maodv_rrep.c k_mroute.c multicast_packet_cache.c \
+	maodv_neighbor.c
 
 SRC_NS = 	debug.c list.c timer_queue.c aodv_socket.c aodv_hello.c \
 		aodv_neighbor.c aodv_timeout.c routing_table.c seek_list.c \
@@ -33,7 +36,8 @@
 # Comment out to disable debug operation...
 DEBUG=-g -DDEBUG
 
-DEFS=#-DUSE_IW_SPY
+DEFS= -DMAODV #-DUSE_IW_SPY
+
 CFLAGS=$(OPTS) $(DEBUG) $(DEFS)
 
 ifneq (,$(findstring USE_IW_SPY,$(DEFS)))
@@ -63,13 +67,14 @@
 # These are the options for the kernel modules:
 #==============================================
 KINC=-nostdinc $(shell $(CC) -print-search-dirs | sed -ne 's/install: \(.*\)/-I \1include/gp') -I/lib/modules/$(KERNEL)/build/include
-KDEFS=-D__KERNEL__ -DMODULE
+KDEFS=-D__KERNEL__ -DMODULE -DMAODV
 KCFLAGS=-Wall -O2 $(KDEFS) $(KINC)
 KCFLAGS_ARM =-Wall -O2 -D__KERNEL__ -DMODULE $(KINC)
 
-.PHONY: default clean install uninstall depend tags aodvd-arm docs
+# .PHONY used to have a docs target in it, I removed it, we got no docs...
+.PHONY: default clean install uninstall depend tags aodvd-arm
 
-default: aodvd kaodv.o
+default: aodvd kaodv.o kinject.o
 
 all: default
 
@@ -106,6 +111,10 @@
 kaodv.o: kaodv.c
 	$(CC) $(KCFLAGS) -c -o $@ $<
 
+# Kernel module for packet injection:
+kinject.o: kinject.c
+	$(CC) $(KCFLAGS) -c -o $@ $<
+
 kaodv-arm.o: kaodv.c
 	$(ARM_CC) $(KCFLAGS_ARM) -c -o $(@:%-arm.o=%.o) $<
 tags:
@@ -117,6 +126,7 @@
 	@echo "Updating Makefile dependencies..."
 	@makedepend -Y./ -- $(DEFS) -- $(SRC) &>/dev/null
 	@makedepend -a -Y./ -- $(KDEFS) kaodv.c &>/dev/null
+	@makedepend -a -Y./ -- $(KDEFS) kinject.c &>/dev/null
 
 install: all
 	install -s -m 755 aodvd /usr/sbin/aodvd
@@ -124,14 +134,16 @@
 		mkdir /lib/modules/$(KERNEL)/aodv; \
 	fi
 	install -m 644 kaodv.o /lib/modules/$(KERNEL)/aodv/kaodv.o
+	install -m 644 kinject.o /lib/modules/$(KERNEL)/aodv/kinject.o
 
 	/sbin/depmod -a
 uninstall:
 	rm -f /usr/sbin/aodvd
 	rm -rf /lib/modules/$(KERNEL)/aodv
 
-docs:
-	cd docs && $(MAKE) all
+# Commented out, we don't have any documentation... yet.
+#docs:
+#	cd docs && $(MAKE) all
 clean: 
 	rm -f aodvd *~ *.o core *.log libaodv-uu.a endian endian.h
 #cd docs && $(MAKE) clean
diff -urNb aodv-uu-0.7.2/TODO.maodv maodv-umd-0.7.2/TODO.maodv
--- aodv-uu-0.7.2/TODO.maodv	Wed Dec 31 19:00:00 1969
+++ maodv-umd-0.7.2/TODO.maodv	Wed Jun 25 17:46:09 2003
@@ -0,0 +1,20 @@
+MAODV TODO
+? expire unactivated nexthops
+* out of spec. umd additions
+  * mact-ack
+  * tree optimization
+* ns-2 maybe...
+* more tests...
+
+MAODV KNOWN LIMITATIONS
+* one way link breaks
+* cannot handle multiple interfaces (although the protocol is
+  at least ill-definied when multiple interfaces are used)
+
+CONCERNS AODV-UU
+* ratelimiting seems broken.
+* setting the d flag for RREQ breaks things.  Incorrect destination 
+  reply code.
+
+DRAW STUFF
+* draw-all needs per-group timeouts
diff -urNb aodv-uu-0.7.2/aodv_hello.c maodv-umd-0.7.2/aodv_hello.c
--- aodv-uu-0.7.2/aodv_hello.c	Mon May 26 16:45:49 2003
+++ maodv-umd-0.7.2/aodv_hello.c	Wed Jun 25 17:46:09 2003
@@ -106,14 +106,15 @@
 	for (i = 0; i < MAX_NR_INTERFACES; i++) {
 	    if (!DEV_NR(i).enabled)
 		continue;
-#ifdef DEBUG_HELLO
+/* #ifdef DEBUG_HELLO */
 	    DEBUG(LOG_DEBUG, 0, "sending Hello to %s",
 		  ip_to_str(AODV_BROADCAST));
-#endif
+/* #endif */
 	    rrep = rrep_create(flags, 0, 0, DEV_NR(i).ipaddr,
 			       this_host.seqno,
 			       DEV_NR(i).ipaddr,
-			       ALLOWED_HELLO_LOSS * HELLO_INTERVAL);
+			       ALLOWED_HELLO_LOSS * HELLO_INTERVAL,
+                               0 );
 
 	    /* Assemble a RREP extension which contain our neighbor set... */
 	    if (unidir_hack) {
@@ -167,7 +168,6 @@
     }
 }
 
-
 /* Process a hello message */
 void NS_CLASS hello_process(RREP * hello, int rreplen, unsigned int ifindex)
 {
@@ -232,10 +232,10 @@
 	ext = AODV_EXT_NEXT(ext);
     }
 
-#ifdef DEBUG_HELLO
+/* #ifdef DEBUG_HELLO */
     DEBUG(LOG_DEBUG, 0, "rcvd HELLO from %s, seqno %lu",
 	  ip_to_str(hello_dst), hello_seqno);
-#endif
+/* #endif */
     /* This neighbor should only be valid after receiving 3
        consecutive hello messages... */
     if (receive_n_hellos)
@@ -289,6 +289,71 @@
     return;
 }
 
+/* Process a broadcast message */
+void NS_CLASS bcast_process(u_int32_t addr,
+    int ifindex)
+{
+    u_int32_t hello_interval = HELLO_INTERVAL;
+    u_int32_t timeout;
+    u_int8_t state, flags = 0;
+    rt_table_t *rt;
+    struct timeval now;
+
+    gettimeofday(&now, NULL);
+
+    DEBUG(LOG_DEBUG, 0, "rcvd BCAST from %s",
+	  ip_to_str(addr));
+
+    /* This neighbor should only be valid after receiving 3
+       consecutive hello messages... */
+    if (receive_n_hellos)
+	state = INVALID;
+    else
+	state = VALID;
+
+    timeout = ALLOWED_HELLO_LOSS * hello_interval + ROUTE_TIMEOUT_SLACK;
+
+    if ((rt = rt_table_find(addr)) == NULL) {
+	/* No active or expired route in the routing table. So we add a
+	   new entry... */
+	
+        /* seqno == 0 because we have no idea... */
+	rt = rt_table_insert(addr, addr, 1, 0, timeout,
+				 state, flags, ifindex);
+	
+	if (flags & RT_UNIDIR)
+	    DEBUG(LOG_INFO, 0, "%s new NEIGHBOR, link UNI-DIR",
+	      ip_to_str(rt->dest_addr));
+	else
+	    DEBUG(LOG_INFO, 0, "%s new NEIGHBOR!", ip_to_str(rt->dest_addr));
+
+	rt->hello_cnt = 1;
+    } else {
+
+	if ((flags & RT_UNIDIR) && rt->state == VALID && rt->hcnt > 1) {
+	    goto hello_update;
+	}
+
+	if (receive_n_hellos && rt->hello_cnt < (receive_n_hellos - 1)) {
+	    if (timeval_diff(&now, &rt->last_hello_time) <
+		(long) (hello_interval + hello_interval / 2))
+		rt->hello_cnt++;
+	    else
+		rt->hello_cnt = 1;
+
+	    rt->last_hello_time = now;
+	    return;
+	}
+	rt_table_update(rt, addr, 1, rt->dest_seqno, timeout, VALID, 
+			flags);
+    }
+
+  hello_update:
+
+    hello_update_timeout(rt, ALLOWED_HELLO_LOSS * hello_interval);
+    rt->last_hello_time = now;
+    return;
+}
 
 #define HELLO_DELAY 50		/* The extra time we should allow an hello
 				   message to take (due to processing) before
diff -urNb aodv-uu-0.7.2/aodv_hello.h maodv-umd-0.7.2/aodv_hello.h
--- aodv-uu-0.7.2/aodv_hello.h	Thu May 22 19:11:34 2003
+++ maodv-umd-0.7.2/aodv_hello.h	Wed Jun 25 17:46:09 2003
@@ -38,8 +38,7 @@
 void hello_stop();
 void hello_send(void *arg);
 void hello_process(RREP * hello, int rreplen, unsigned int ifindex);
-void hello_process_non_hello(AODV_msg * aodv_msg, u_int32_t source,
-			     unsigned int ifindex);
+void NS_CLASS bcast_process(u_int32_t addr, int ifindex);
 NS_INLINE void hello_update_timeout(rt_table_t * rt, long time);
 
 #ifdef NS_PORT
diff -urNb aodv-uu-0.7.2/aodv_neighbor.c maodv-umd-0.7.2/aodv_neighbor.c
--- aodv-uu-0.7.2/aodv_neighbor.c	Tue May 27 12:32:58 2003
+++ maodv-umd-0.7.2/aodv_neighbor.c	Wed Jun 25 17:46:09 2003
@@ -43,6 +43,7 @@
     rt_table_t *rt = NULL;
     u_int32_t seqno = 0;
     int flags = 0;
+    struct timeval now;
 
     /* According to the draft, the seqno should always be set to
      * invalid when adding neighbors... */
@@ -69,6 +70,12 @@
 	rt_table_update(rt, source, 1, seqno, ACTIVE_ROUTE_TIMEOUT,
 			VALID, flags);
     }
+
+    gettimeofday(&now, NULL);
+    hello_update_timeout(rt, ALLOWED_HELLO_LOSS * HELLO_INTERVAL);
+    rt->last_hello_time = now;
+
+    DEBUG( LOG_DEBUG, 0, "Updated bcast/HELLO timer for %s", ip_to_str( source ) );
 
     if (!llfeedback) 
 	hello_update_timeout(rt, ALLOWED_HELLO_LOSS * HELLO_INTERVAL);
diff -urNb aodv-uu-0.7.2/aodv_rrep.c maodv-umd-0.7.2/aodv_rrep.c
--- aodv-uu-0.7.2/aodv_rrep.c	Tue May 27 12:32:58 2003
+++ maodv-umd-0.7.2/aodv_rrep.c	Wed Jun 25 17:46:09 2003
@@ -38,6 +38,13 @@
 
 extern int unidir_hack, optimized_hellos, llfeedback;
 
+#ifdef MAODV
+#include "maodv_rrep.h"
+#include "maodv_ext.h"
+#include "maodv_mact.h"
+#include "seek_list.h"
+#endif
+
 #endif
 
 RREP *NS_CLASS rrep_create(u_int8_t flags,
@@ -46,9 +53,14 @@
 			   u_int32_t dest_addr,
 			   u_int32_t dest_seqno,
 			   u_int32_t orig_addr, 
-			   u_int32_t life)
+			   u_int32_t life,
+                           u_int32_t grp_addr )
 {
     RREP *rrep;
+#ifdef MAODV
+    int size = RREP_SIZE;
+    GRP_MERGE_EXT * gme;
+#endif
 
     rrep = (RREP *) aodv_socket_new_msg();
     rrep->type = AODV_RREP;
@@ -66,6 +78,19 @@
     if (flags & RREP_ACK)
 	rrep->a = 1;
 
+#ifdef MAODV
+    if ( rrep->r ) {
+        /* add group merge extension */
+        gme = (GRP_MERGE_EXT *) ((char *)rrep + size);
+        gme->type = GME_TYPE;
+        gme->length = GME_LENGTH;
+        gme->res = 0;
+        gme->grp_addr = htonl(grp_addr);
+
+        size += GME_LENGTH + 2;    /* length + "header" */
+    }
+#endif /* MAODV */
+
     /* Don't print information about hello messages... */
 #ifdef DEBUG_OUTPUT
     if (dest_addr != orig_addr) {
@@ -107,13 +132,15 @@
     timer_remove(&rt->ack_timer);
 }
 
-void NS_CLASS rrep_send(rt_table_t * rev_rt, rt_table_t * fwd_rt)
+void NS_CLASS rrep_send(rt_table_t * rev_rt, rt_table_t * fwd_rt, 
+    u_int16_t flags, u_int32_t grp_addr )
 {
     RREP *rrep;
-    u_int8_t rrep_flags = 0;
+    u_int8_t rrep_flags = flags;
     u_int32_t seqno, dest, lifetime;
     int hcnt;
     struct timeval now;
+    int size = RREP_SIZE;
 
     if (!rev_rt) {
 	DEBUG(LOG_WARNING, 0, "Can't send RREP, rev_rt = NULL!");
@@ -165,9 +192,16 @@
 	  ip_to_str(dest));
 
     rrep = rrep_create(rrep_flags, 0, hcnt, dest, seqno, rev_rt->dest_addr,
-		       lifetime);
+		       lifetime, grp_addr );
+
+#ifdef MAODV
+    if ( rrep_flags & RREP_REPAIR ) {
+        DEBUG( LOG_DEBUG, 0, "RREP_GRP_MERGE_EXT set." );
+        size += GRP_MERGE_EXT_SIZE;
+    }
+#endif /* MAODV */
 
-    aodv_socket_send((AODV_msg *) rrep, rev_rt->next_hop, RREP_SIZE, MAXTTL,
+    aodv_socket_send((AODV_msg *) rrep, rev_rt->next_hop, size, MAXTTL,
 		     &DEV_IFINDEX(rev_rt->ifindex));
 
     /* Update precursor lists */
@@ -181,7 +215,7 @@
 }
 
 void NS_CLASS rrep_forward(RREP * rrep, rt_table_t * rev_rt,
-			   rt_table_t * fwd_rt, int ttl)
+			   rt_table_t * fwd_rt, int ttl, int size )
 {
     /* Sanity checks... */
     if (!fwd_rt || !rev_rt) {
@@ -220,10 +254,10 @@
 	}
     }
 
-    rrep = (RREP *) aodv_socket_queue_msg((AODV_msg *) rrep, RREP_SIZE);
+    rrep = (RREP *) aodv_socket_queue_msg((AODV_msg *) rrep, size);
     rrep->hcnt = fwd_rt->hcnt;	/* Update the hopcount */
 
-    aodv_socket_send((AODV_msg *) rrep, rev_rt->next_hop, RREP_SIZE, ttl,
+    aodv_socket_send((AODV_msg *) rrep, rev_rt->next_hop, size, ttl,
 		     &DEV_IFINDEX(rev_rt->ifindex));
 
     precursor_add(fwd_rt, rev_rt->next_hop);
@@ -239,6 +273,16 @@
     u_int32_t rrep_dest, rrep_orig, rrep_lifetime, rrep_seqno, rrep_new_hcnt;
     u_int8_t pre_repair_hcnt = 0, pre_repair_flags = 0;
     rt_table_t *fwd_rt, *rev_rt;
+    int size = rreplen;
+
+    AODV_ext * ext;
+
+#ifdef MAODV
+    GRP_MERGE_EXT * gmg_ext = NULL;
+    u_int32_t grp_addr;
+
+    grp_addr = 0;
+#endif
 
     /* Convert to correct byte order on affeected fields: */
     rrep_dest = ntohl(rrep->dest_addr);
@@ -265,6 +309,47 @@
     log_pkt_fields((AODV_msg *) rrep);
 #endif
     
+    ext = (AODV_ext *) ((char *) rrep + RREP_SIZE);
+
+    while( rreplen > (int) RREP_SIZE ) {
+        switch(ext->type) {
+#ifdef MAODV
+        case RREP_GRP_MERGE_EXT:
+            DEBUG(LOG_INFO, 0, "RREP includes group merge extension." );
+            gmg_ext = (GRP_MERGE_EXT *) ext;
+            if ( gmg_ext->length != GME_LENGTH ) {
+                DEBUG(LOG_DEBUG, 0, "Wrong length[%d] for gmg_ext.", 
+                    gmg_ext->length );
+                gmg_ext = NULL;
+            } else {
+                grp_addr = ntohl(gmg_ext->grp_addr);
+            }
+            break;
+#endif
+        default:
+            log(LOG_WARNING, 0, __FUNCTION__, "Unknown extension type %d",
+                ext->type);
+            break;
+        }
+        rreplen -= AODV_EXT_SIZE(ext);
+        ext = AODV_EXT_NEXT(ext);
+    }
+
+#ifdef MAODV
+    if ( IN_MULTICAST( rrep_dest ) ) {
+        DEBUG(LOG_DEBUG, 0, "MAODV rrep process." );
+        maodv_rrep_process( rrep, rreplen, ip_src, ip_dst, ip_ttl, 
+            ifindex, size);
+
+#ifndef AODVUU_LL_FEEDBACK
+        if (optimized_hellos)
+            hello_start();
+#endif
+
+        return;
+    }
+#endif
+
     /* ---------- CHECK IF WE SHOULD MAKE A FORWARD ROUTE ------------ */
     
     fwd_rt = rt_table_find(rrep_dest);
@@ -288,8 +373,13 @@
 	    DEBUG(LOG_DEBUG, 0, "Dropping RREP, fwd_rt->hcnt=%d fwd_rt->seqno=%ld",
 		  fwd_rt->hcnt, fwd_rt->dest_seqno);
 	}
+
+        if ( rrep->r ) {
+            DEBUG(LOG_DEBUG, 0, "Special RREP for group merge. Accepting despite an existing route." );
+        } else {
 	return;
     }
+    }
     
     
     /* If the RREP_ACK flag is set we must send a RREP
@@ -327,11 +417,102 @@
 				     RERR_CALC_SIZE(rerr), 1,
 				     &DEV_IFINDEX(fwd_rt->ifindex));
 	    }
+	} else {
+#ifdef MAODV
+            mrt_table_t *mrt;
+
+            if ( (gmg_ext != NULL) && 
+                 (mrt = mrt_table_find(grp_addr)) && 
+                 rrep->r ) {
+                mrt_nexthop_t *upstream;
+                
+                DEBUG(LOG_DEBUG, 0, "in gmg_ext processing section");
+                DEBUG(LOG_DEBUG, 0, "grp_addr: %s", ip_to_str(grp_addr));
+
+                /* make ip_src upstream */
+                upstream=mrt_table_get_activated_upstream(mrt);
+                if(upstream!=NULL){
+                    mrt_nexthop_deactivate(mrt, upstream->addr);
+                }
+
+                upstream=mrt_nexthop_find(mrt, ip_src);
+                if(upstream==NULL){
+                    upstream=mrt_nexthop_add(mrt, ip_src, MRT_UPSTREAM, 0);
+                }
+
+                if(upstream->activated){
+                    mrt_nexthop_deactivate(mrt, upstream->addr);
+                }
+                upstream->direction=MRT_UPSTREAM;
+
+                mrt_nexthop_activate(mrt, upstream->addr);
+                
+                /* send mact */
+                mact_send(MACT_JOIN, 1, grp_addr, ip_src, 1);
+
+                /* route is repaired */
+                mrt->in_repair=0;
+                
+                /* stop being leader */
+                mrt->am_leader = 0;
+
+                DEBUG( LOG_DEBUG, 0, "Giving up leadership to other leader." );
+                DEBUG( LOG_DEBUG, 0, "grp_addr: %s", ip_to_str(grp_addr) );
+
+                seek_list_remove_mcast(rrep_dest, grp_addr);
+            }
+#endif /* MAODV */
 	}
     } else {
 	/* --- Here we FORWARD the RREP on the REVERSE route --- */
 	if (rev_rt && rev_rt->state == VALID) {
-	    rrep_forward(rrep, rev_rt, fwd_rt, --ip_ttl);
+#ifdef MAODV
+            if ( rrep->r ) {
+                /* make old activated upstream a downstream? or let mact? */
+                mrt_table_t *mrt;
+
+                DEBUG(LOG_DEBUG, 0, "grp_addr: %s", ip_to_str(grp_addr));
+
+                if ( (gmg_ext != NULL) && 
+                     (mrt = mrt_table_find(grp_addr)) && 
+                     rrep->r ) {
+                    mrt_nexthop_t *upstream;
+
+                    DEBUG(LOG_DEBUG, 0, "in gmg_ext processing section");
+                    DEBUG(LOG_DEBUG, 0, "grp_addr: %s", ip_to_str(grp_addr));
+
+                    /* make ip_src upstream */
+                    upstream=mrt_table_get_activated_upstream(mrt);
+                    if(upstream!=NULL){
+                        mrt_nexthop_deactivate(mrt, upstream->addr);
+                    }
+
+                    upstream=mrt_nexthop_find(mrt, ip_src);
+                    if(upstream==NULL){
+                        upstream=mrt_nexthop_add(mrt, ip_src, 
+                            MRT_UPSTREAM, 0);
+                    }
+
+                    if(upstream->activated){
+                        mrt_nexthop_deactivate(mrt, upstream->addr);
+                    }
+                    upstream->direction=MRT_UPSTREAM;
+
+                    mrt_table_start_routing(mrt);
+
+                    mrt_nexthop_activate(mrt, upstream->addr);
+
+                    /* send mact */
+                    mact_send(MACT_JOIN, 1, grp_addr, ip_src, 1);
+                
+                    /* update GL information */
+                    /* GRPH->u */
+                }
+            }
+            rrep_forward(rrep, rev_rt, fwd_rt, --ip_ttl, size);
+#else  /* MAODV */
+	    rrep_forward(rrep, rev_rt, fwd_rt, --ip_ttl, size);
+#endif /* MAODV */
 	} else {
 	    DEBUG(LOG_DEBUG, 0, "Could not forward RREP - NO ROUTE!!!");
 	}
diff -urNb aodv-uu-0.7.2/aodv_rrep.h maodv-umd-0.7.2/aodv_rrep.h
--- aodv-uu-0.7.2/aodv_rrep.h	Thu May 22 19:11:35 2003
+++ maodv-umd-0.7.2/aodv_rrep.h	Wed Jun 25 17:46:09 2003
@@ -72,12 +72,14 @@
 		  u_int8_t prefix,
 		  u_int8_t hcnt,
 		  u_int32_t dest_addr,
-		  u_int32_t dest_seqno, u_int32_t orig_addr, u_int32_t life);
+		  u_int32_t dest_seqno, u_int32_t orig_addr, u_int32_t life,
+                  u_int32_t grp_addr );
 
 RREP_ack *rrep_ack_create();
-void rrep_send(rt_table_t * rev_rt, rt_table_t * fwd_rt);
+void rrep_send(rt_table_t * rev_rt, rt_table_t * fwd_rt, u_int16_t flags, 
+    u_int32_t grp_addr );
 void rrep_forward(RREP * rrep, rt_table_t * rev_rt, rt_table_t * fwd_rt,
-		  int ttl);
+		  int ttl, int size );
 void rrep_process(RREP * rrep, int rreplen, u_int32_t ip_src, u_int32_t ip_dst,
 		  int ip_ttl, unsigned int ifindex);
 void rrep_ack_process(RREP_ack * rrep_ack, int rreplen, u_int32_t ip_src,
diff -urNb aodv-uu-0.7.2/aodv_rreq.c maodv-umd-0.7.2/aodv_rreq.c
--- aodv-uu-0.7.2/aodv_rreq.c	Thu May 22 19:11:35 2003
+++ maodv-umd-0.7.2/aodv_rreq.c	Fri Dec  5 17:42:32 2003
@@ -25,6 +25,7 @@
 #include "aodv-uu.h"
 #else
 #include <netinet/in.h>
+#include <linux/route.h>
 #include "aodv_rreq.h"
 #include "aodv_rrep.h"
 #include "routing_table.h"
@@ -36,6 +37,14 @@
 #include "seek_list.h"
 #include "defs.h"
 #include "debug.h"
+
+
+#ifdef MAODV
+#include "multicast_routing_table.h"
+#include "maodv_rreq.h"
+#include "maodv_ext.h"
+#endif
+
 #endif
 
 /* Comment this to remove packet field output: */
@@ -57,9 +66,15 @@
 #endif
 
 RREQ *NS_CLASS rreq_create(u_int8_t flags, u_int32_t dest_addr,
-			   u_int32_t dest_seqno, u_int32_t orig_addr)
+			   u_int32_t dest_seqno, u_int32_t orig_addr,
+                           u_int16_t grp_hcnt, u_int32_t grp_addr )
 {
     RREQ *rreq;
+#ifdef MAODV
+    int size = RREQ_SIZE;
+    GRP_REBUILD_EXT * gre;
+    GRP_MERGE_EXT * gme;
+#endif
 
     rreq = (RREQ *) aodv_socket_new_msg();
     rreq->type = AODV_RREQ;
@@ -86,6 +101,30 @@
     if (flags & RREQ_UNKNOWN_SEQNO)
 	rreq->u = 1;
 
+#ifdef MAODV
+
+    if (flags & RREQ_GRP_REBUILD ) {
+        gre = (GRP_REBUILD_EXT *) ((char *) rreq + size);
+        gre->type = GRE_TYPE;
+        gre->length = GRE_LENGTH;
+        gre->grp_hcnt = htons(grp_hcnt);
+
+        size += GRP_REBUILD_EXT_SIZE;
+    }
+
+    if ( rreq->r && rreq->j ) {
+        /* add merge extension */
+        gme = (GRP_MERGE_EXT *) ((char *) rreq + size);
+        gme->type = GME_TYPE;
+        gme->length = GME_LENGTH;
+        gme->res = 0;
+        gme->grp_addr = htonl(grp_addr);
+
+        size += GRP_MERGE_EXT_SIZE;
+    }
+
+#endif /* MAODV */
+
     DEBUG(LOG_DEBUG, 0, "Assembled RREQ %s", ip_to_str(dest_addr));
 #ifdef DEBUG_OUTPUT
     log_pkt_fields((AODV_msg *) rreq);
@@ -94,6 +133,44 @@
     return rreq;
 }
 
+void NS_CLASS rreq_send_ext(u_int32_t dest_addr, u_int32_t dest_seqno, 
+                        int ttl, u_int8_t flags, u_int16_t grp_hcnt,
+                        u_int32_t grp_addr )
+{
+    RREQ *rreq;
+    int i;
+    int size = RREQ_SIZE;
+
+    /* Check if we should force the gratuitous flag... (-g option). */
+    if (rreq_gratuitous)
+	flags |= RREQ_GRATUITOUS;
+
+#ifdef MAODV
+
+    if ( flags & RREQ_GRP_REBUILD ) {
+        DEBUG( LOG_DEBUG, 0, "RREQ_GRP_REBUILD_EXT set." );
+        size += GRP_REBUILD_EXT_SIZE;
+    }
+
+    if ( (flags & RREQ_JOIN) && (flags & RREQ_REPAIR) ) {
+        DEBUG( LOG_DEBUG, 0, "RREQ_GRP_MERGE_EXT set, group %s", ip_to_str(grp_addr) );
+        size += GRP_MERGE_EXT_SIZE;
+    }
+
+#endif /* MAODV */
+
+    /* Broadcast on all interfaces */
+    for (i = 0; i < MAX_NR_INTERFACES; i++) {
+	if (!DEV_NR(i).enabled)
+	    continue;
+	rreq = rreq_create(flags, dest_addr, dest_seqno, DEV_NR(i).ipaddr,
+            grp_hcnt, grp_addr );
+
+	aodv_socket_send((AODV_msg *) rreq, AODV_BROADCAST, size,
+                         ttl, &DEV_NR(i) );
+    }
+}
+
 void NS_CLASS rreq_send(u_int32_t dest_addr, u_int32_t dest_seqno, int ttl,
 			u_int8_t flags)
 {
@@ -108,13 +185,14 @@
     for (i = 0; i < MAX_NR_INTERFACES; i++) {
 	if (!DEV_NR(i).enabled)
 	    continue;
-	rreq = rreq_create(flags, dest_addr, dest_seqno, DEV_NR(i).ipaddr);
+	rreq = rreq_create(flags, dest_addr, dest_seqno, DEV_NR(i).ipaddr, 
+            0, 0 );
 	aodv_socket_send((AODV_msg *) rreq, AODV_BROADCAST, RREQ_SIZE, ttl,
 			 &DEV_NR(i));
     }
 }
 
-void NS_CLASS rreq_forward(RREQ * rreq, int ttl)
+void NS_CLASS rreq_forward(RREQ * rreq, int ttl, int size )
 {
     int i;
     /* FORWARD the RREQ if the TTL allows it. */
@@ -122,7 +200,7 @@
 	  ip_to_str(ntohl(rreq->orig_addr)), ntohl(rreq->rreq_id));
 
     /* Queue the received message in the send buffer */
-    rreq = (RREQ *) aodv_socket_queue_msg((AODV_msg *) rreq, RREQ_SIZE);
+    rreq = (RREQ *) aodv_socket_queue_msg((AODV_msg *) rreq, size );
 
     rreq->hcnt++;		/* Increase hopcount to account for
 				 * intermediate route */
@@ -131,10 +209,35 @@
     for (i = 0; i < MAX_NR_INTERFACES; i++) {
 	if (!DEV_NR(i).enabled)
 	    continue;
-	aodv_socket_send((AODV_msg *) rreq, AODV_BROADCAST, RREQ_SIZE, ttl,
+	aodv_socket_send((AODV_msg *) rreq, AODV_BROADCAST, size, ttl,
+			 &DEV_NR(i));
+    }
+}
+
+#ifdef MAODV
+void NS_CLASS rreq_forward_uni(RREQ * rreq, u_int32_t dest, int ttl, 
+    int size )
+{
+    int i;
+    /* FORWARD the RREQ if the TTL allows it. */
+    DEBUG(LOG_INFO, 0, "forwarding RREQ src=%s, rreq_id=%lu",
+	  ip_to_str(ntohl(rreq->orig_addr)), ntohl(rreq->rreq_id));
+
+    /* Queue the received message in the send buffer */
+    rreq = (RREQ *) aodv_socket_queue_msg((AODV_msg *) rreq, size );
+
+    rreq->hcnt++;		/* Increase hopcount to account for
+				 * intermediate route */
+
+    /* Send out on all interfaces */
+    for (i = 0; i < MAX_NR_INTERFACES; i++) {
+	if (!DEV_NR(i).enabled)
+	    continue;
+	aodv_socket_send((AODV_msg *) rreq, AODV_BROADCAST, size, ttl,
 			 &DEV_NR(i));
     }
 }
+#endif /* MAODV */
 
 void NS_CLASS rreq_process(RREQ * rreq, int rreqlen, u_int32_t ip_src,
 			   u_int32_t ip_dst, int ip_ttl, unsigned int ifindex)
@@ -144,6 +247,14 @@
     rt_table_t *rev_rt, *fwd_rt = NULL;
     u_int32_t rreq_orig, rreq_dest, rreq_orig_seqno, rreq_dest_seqno;
     u_int32_t rreq_id, rreq_new_hcnt, life;
+    int size;
+#ifdef MAODV
+    GRP_REBUILD_EXT *grb_ext=NULL;
+    GRP_MERGE_EXT *gmg_ext=NULL;
+    u_int32_t grp_addr;
+
+    grp_addr = 0;
+#endif
 
     rreq_id = ntohl(rreq->rreq_id);
     rreq_dest = ntohl(rreq->dest_addr);
@@ -152,6 +263,7 @@
     rreq_orig_seqno = ntohl(rreq->orig_seqno);
     rreq_new_hcnt = rreq->hcnt + 1;
 
+    size = rreqlen;
 
     DEBUG(LOG_DEBUG, 0, "ip_src=%s rreq_orig=%s rreq_dest=%s",
 	  ip_to_str(ip_src), ip_to_str(rreq_orig), ip_to_str(rreq_dest));
@@ -193,14 +305,36 @@
 	    DEBUG(LOG_INFO, 0, "RREQ include EXTENSION");
 	    /* Do something here */
 	    break;
+#ifdef MAODV
+        case RREQ_GRP_REBUILD_EXT:
+            DEBUG(LOG_INFO, 0, "RREQ includes group rebuild extension");
+            grb_ext=(GRP_REBUILD_EXT*)ext;
+            if(grb_ext->length!=GRE_LENGTH) {
+                grb_ext=NULL;
+            }
+            break;
+        case RREQ_GRP_MERGE_EXT:
+            DEBUG(LOG_INFO, 0, "RREQ includes group merge extension" );
+            gmg_ext = (GRP_MERGE_EXT *) ext;
+            if ( gmg_ext->length != GME_LENGTH ) {
+                gmg_ext = NULL;
+            } else {
+                grp_addr = ntohl(gmg_ext->grp_addr);
+            }
+            break;
+#endif
 	default:
-	    log(LOG_WARNING, 0, __FUNCTION__, "Unknown extension type %d",
-		ext->type);
+	    log(LOG_WARNING, 0, __FUNCTION__, "Unknown extension type." );
 	    break;
 	}
 	rreqlen -= AODV_EXT_SIZE(ext);
 	ext = AODV_EXT_NEXT(ext);
     }
+
+#ifdef MAODV
+    DEBUG(LOG_DEBUG, 0, "grp_addr: %s", ip_to_str(grp_addr));
+#endif /* MAODV */
+
 #ifdef DEBUG_OUTPUT
     log_pkt_fields((AODV_msg *) rreq);
 #endif
@@ -239,14 +373,17 @@
     }
     /**** END updating/creating REVERSE route ****/
 
-    /* BAD HACK for Internet gateway support: */
-    if (internet_gw_mode &&
-	this_host.gateway_mode &&
-	(rreq_dest & DEV_IFINDEX(ifindex).netmask) !=
-	(DEV_IFINDEX(ifindex).ipaddr & DEV_IFINDEX(ifindex).netmask)) {
-	rrep_send(rev_rt, NULL);
+#ifdef MAODV
+    if ( IN_MULTICAST(rreq_dest) ) {
+        DEBUG(LOG_DEBUG, 0, "MAODV RREQ process.");
+        /* TODO: Added multicast rreq support. */
+        maodv_rreq_process( rreq, rreqlen, ip_src, ip_dst,
+            ip_ttl, ifindex, grb_ext, size );
+
 	return;
     }
+#endif
+
     /* Are we the destination of the RREQ?, if so we should immediately send a
        RREP.. */
     if (rreq_dest == DEV_IFINDEX(ifindex).ipaddr) {
@@ -254,15 +391,47 @@
 	/* WE are the RREQ DESTINATION. Update the node's own
 	   sequence number to the maximum of the current seqno and the
 	   one in the RREQ. */
-	if (!rreq->u && this_host.seqno < rreq_dest_seqno)
-	    this_host.seqno = rreq_dest_seqno;
+        if (!rreq->u && this_host.seqno == rreq_dest_seqno)
+	    this_host.seqno++;
 
-	rrep_send(rev_rt, NULL);
+#ifdef MAODV
+        if ((rreq->j) && (rreq->r) && (gmg_ext != NULL)) {
+            mrt_table_t *mrt;
+            mrt=mrt_table_find(grp_addr);
+            if(mrt->am_leader && !mrt->in_repair){
+                /* recieved a rreq because i'm leader */
+                DEBUG(LOG_DEBUG, 0, "Received a RREQ[j] for me.  Should send RREP for group.");
+                /* make GRPH flag update */
+                mrt->grph_update_cnt=2;
+                rrep_send(rev_rt, NULL, RREP_REPAIR, grp_addr );
+            }
+        } else {
+            rrep_send(rev_rt, NULL, 0, 0);
+        }
+#else  /* MAODV */
+        rrep_send(rev_rt, NULL, 0, 0);
+#endif /* MAODV */
 
     } else {
-	/* We are an INTERMEDIATE node. - check if we have an active
-	 * route entry */
+        /* We are an intermediate node, first check if being gatewayed */
+
+        /* Internet gateway support: */
+        if (internet_gw_mode && this_host.gateway_mode &&
+	    (rreq_dest & DEV_IFINDEX(ifindex).netmask) !=
+            (DEV_IFINDEX(ifindex).ipaddr & DEV_IFINDEX(ifindex).netmask)) {
+		printf("In here!!!\n");
+            int metric = get_route_metric(rreq->dest_addr);
+            if(metric >= 0) {
+			printf("Good metric!!!\n");
+                RREP *rrep = rrep_create(0, 0, ++metric, rreq_dest,
+                    ++this_host.seqno, rev_rt->dest_addr, MY_ROUTE_TIMEOUT, 0);
+                aodv_socket_send((AODV_msg*)rrep, rev_rt->next_hop, RREP_SIZE,
+                    MAXTTL, &DEV_IFINDEX(rev_rt->ifindex));
+                return;
+            }
+        }
 
+	/* check if we have an active route entry */
 	fwd_rt = rt_table_find(rreq_dest);
 
 	if (fwd_rt && fwd_rt->state == VALID && !rreq->d &&
@@ -273,12 +442,12 @@
 	       enough (our destination sequence number for that route is
 	       larger than the one in the RREQ). */
 
-	    rrep_send(rev_rt, fwd_rt);
+	    rrep_send(rev_rt, fwd_rt, 0, 0);
 
 	    /* If the GRATUITOUS flag is set, we must also unicast a
 	       gratuitous RREP to the destination. */
 	    if (rreq->g) {
-		rrep_send(fwd_rt, rev_rt);
+		rrep_send(fwd_rt, rev_rt, 0, 0);
 
 		DEBUG(LOG_INFO, 0, "Sending G-RREP to %s with rte to %s",
 		      ip_to_str(rreq_dest), ip_to_str(rreq_orig));
@@ -292,7 +461,38 @@
 		rreq->u = 0;
 	    }
 
-	    rreq_forward(rreq, --ip_ttl);
+#ifdef MAODV
+            if (( rreq->j ) && ( rreq->r ) && (gmg_ext != NULL)) {
+                mrt_table_t * mrt;
+                mrt_nexthop_t * upstream;
+
+                /* if I am part of group, unicast up. */
+                /* else regular rreq */
+                DEBUG( LOG_DEBUG, 0, "Recieved a RREQ[jr], forwarding." );
+
+                mrt = mrt_table_find( grp_addr );
+                if (( mrt != NULL ) && 
+                    ( mrt->grp_leader_addr == rreq_dest ) &&
+                    ( mrt->is_router ) ) {
+                    /* one of the members of the >ip tree */
+
+                    /* find activated upstream */
+                    upstream = mrt_table_get_activated_upstream( mrt );
+                    if ( ! upstream ) {
+                        DEBUG( LOG_DEBUG, 0, "Odd State: no activated upstream, but not leader..." );
+                    } else {
+                        rreq_forward_uni(rreq, upstream->addr, --ip_ttl, size );
+                    }
+                } else {
+                    /* not part of > ip tree, just forward along */
+                    rreq_forward(rreq, --ip_ttl, size );              
+                }
+            } else {
+                rreq_forward(rreq, --ip_ttl, size );
+            }
+#else /* MAODV */
+                rreq_forward(rreq, --ip_ttl, size );
+#endif /* MAODV */
 
 	} else {
 	    DEBUG(LOG_DEBUG, 0, "RREQ not forwarded - ttl=0");
@@ -303,7 +503,7 @@
 /* Perform route discovery for a unicast destination */
 
 void NS_CLASS rreq_route_discovery(u_int32_t dest_addr, u_int8_t flags,
-				   struct ip_data *ipd)
+				   struct ip_data *ipd, u_int32_t grp_addr)
 {
     struct timeval now;
     rt_table_t *rt;
@@ -311,26 +511,51 @@
     u_int32_t dest_seqno;
     int ttl;
 #define TTL_VALUE ttl
+    u_int16_t grp_hcnt;
+
+#ifdef MAODV
+    mrt_table_t *mrt;
+#endif /* MAODV */
 
     gettimeofday(&now, NULL);
 
+#ifdef MAODV
+    /* for non-merge RREQs, grp_addr should always be zero, so
+       seek_list_find_mcast will act like seek_list_find. */
+    if(seek_list_find_mcast(dest_addr, grp_addr))
+    return;
+#else
     if (seek_list_find(dest_addr))
 	return;
+#endif
 
     /* If we already have a route entry, we use information from it. */
     rt = rt_table_find(dest_addr);
 
+    grp_hcnt = 0;
+
+#ifdef MAODV
+    mrt = NULL;
+    if(IN_MULTICAST(dest_addr)) {
+        mrt = mrt_table_find(dest_addr);
+    }
+#endif
+
     ttl = NET_DIAMETER;		/* This is the TTL if we don't use expanding
 				   ring search */
 
+#ifdef MAODV
+    if((rt == NULL) && (mrt == NULL)) {
+#else
     if (rt == NULL) {
+#endif
 	flags |= RREQ_UNKNOWN_SEQNO;
 	dest_seqno = 0;
 
 	if (expanding_ring_search)
 	    ttl = TTL_START;
 
-    } else {
+    } else if(rt != NULL) {
 
 	if (rt->flags & RT_INV_SEQNO) {
 	    flags |= RREQ_UNKNOWN_SEQNO;
@@ -346,12 +571,44 @@
 	if (timeval_diff(&rt->rt_timer.timeout, &now) <
 	    (2 * NET_TRAVERSAL_TIME))
 	    rt_table_update_timeout(rt, 2 * NET_TRAVERSAL_TIME);
+
+#ifndef MAODV
     }
+#else
+    } else {
 
-    rreq_send(dest_addr, dest_seqno, ttl, flags);
+	if ( mrt->grp_seqno == 0 ) {
+	    flags |= RREQ_UNKNOWN_SEQNO;
+	    dest_seqno = 0;
+	} else
+	    dest_seqno = mrt->grp_seqno;
+
+	if (expanding_ring_search) {
+            if ( mrt->leader_hcnt == 0xff ) {
+                ttl = TTL_START;
+            } else {
+                ttl = mrt->leader_hcnt + TTL_INCREMENT;
+    }
+	}
+
+        grp_hcnt = mrt->leader_hcnt;
+
+	/* A routing table entry waiting for a RREP should not be expunged
+	   before 2 * NET_TRAVERSAL_TIME... */
+        /* CHECK: timeouts not happening yet. */
+        /*
+	if (timeval_diff(&mrt->mrt_timer.timeout, &now) <
+	    (2 * NET_TRAVERSAL_TIME))
+	    mrt_table_update_timeout(mrt, 2 * NET_TRAVERSAL_TIME);
+        */
+    }
+#endif /* MAODV */
+
+    rreq_send_ext(dest_addr, dest_seqno, ttl, flags, grp_hcnt, grp_addr);
 
     /* Remember that we are seeking this destination */
-    seek_entry = seek_list_insert(dest_addr, dest_seqno, ttl, flags, ipd);
+    seek_entry = seek_list_insert(dest_addr, dest_seqno, ttl, flags, ipd, 
+        grp_hcnt, grp_addr);
 
     /* Set a timer for this RREQ */
     if (expanding_ring_search)
@@ -416,7 +673,7 @@
     /* Remember that we are seeking this destination and setup the
        timers */
     seek_entry = seek_list_insert(rt->dest_addr, rt->dest_seqno,
-				  ttl, flags, ipd);
+				  ttl, flags, ipd, 0, 0);
 
     if (expanding_ring_search)
 	timer_set_timeout(&seek_entry->seek_timer,
@@ -528,3 +785,56 @@
     list_detach(&bl->l);
     free(bl);
 }
+
+static int get_mask_bitlen(u_int32_t mask) {
+    int bits = 0;
+    while(mask) {
+        if(mask & 1) {
+            bits++;
+        }
+        mask >>= 1;
+    }
+    return bits;
+}
+
+int get_route_metric(u_int32_t dest_addr) {
+    FILE *routes;
+    char buff[1024];
+    u_int32_t dest, gw, mask, metric, flags;
+    int  valid_entry = 0, valid_metric = -1, valid_bitlen = -1, bitlen;
+
+    /* Open Linux route table for reading */
+    routes = fopen("/proc/net/route", "r");
+    if(routes == NULL) {
+        return -1;
+    }
+
+    /* Read and discard header line */
+    fgets(buff, sizeof(buff), routes);
+    while(!feof(routes)) {
+        fgets(buff, sizeof(buff), routes);
+        /* Iface Destination Gateway Flags RefCnt Use Metric
+         *         Mask MTU Window IRTT */
+        sscanf(buff, "%*s %x %x %x %*x %*x %x %x", &dest, &gw, &flags,
+                &metric, &mask);
+        if((flags & RTF_UP) && ((dest&mask) == (dest_addr&mask))) {
+            bitlen = get_mask_bitlen(mask);
+            if(!valid_entry) {
+                valid_entry++;
+                valid_metric = metric;
+                valid_bitlen = bitlen;
+            } else if(bitlen > valid_bitlen) {
+                valid_metric = metric;
+                valid_bitlen = bitlen;
+            } else if((bitlen == valid_bitlen) && (valid_metric > metric)) {
+                valid_metric = metric;
+            }
+        }
+    }
+    fclose(routes);
+
+    /* If we found a matching, valid route, return its metric; otherwise,
+     * return an invalid metric (-1) */
+    return valid_entry ? metric : -1;
+}
+
diff -urNb aodv-uu-0.7.2/aodv_rreq.h maodv-umd-0.7.2/aodv_rreq.h
--- aodv-uu-0.7.2/aodv_rreq.h	Mon Jun  9 06:43:40 2003
+++ maodv-umd-0.7.2/aodv_rreq.h	Thu Jul 17 18:03:41 2003
@@ -36,6 +36,7 @@
 #define RREQ_GRATUITOUS    0x4
 #define RREQ_DEST_ONLY     0x8
 #define RREQ_UNKNOWN_SEQNO 0x10
+#define RREQ_GRP_REBUILD   0x20
 
 typedef struct {
     u_int8_t type;
@@ -84,25 +85,34 @@
 
 #ifndef NS_NO_DECLARATIONS
 RREQ *rreq_create(u_int8_t flags, u_int32_t dest_addr,
-		  u_int32_t dest_seqno, u_int32_t orig_addr);
+		  u_int32_t dest_seqno, u_int32_t orig_addr,
+          u_int16_t grp_hcnt, u_int32_t grpaddr);
+void rreq_send_ext(u_int32_t dest_addr, u_int32_t dest_seqno, int ttl,
+          u_int8_t flags, u_int16_t grp_hcnt, u_int32_t grp_addr);
 void rreq_send(u_int32_t dest_addr, u_int32_t dest_seqno, int ttl,
 	       u_int8_t flags);
-void rreq_forward(RREQ * rreq, int ttl);
+void rreq_forward(RREQ * rreq, int ttl, int size);
 void rreq_process(RREQ * rreq, int rreqlen, u_int32_t ip_src,
 		  u_int32_t ip_dst, int ip_ttl, unsigned int ifindex);
 void rreq_route_discovery(u_int32_t dest_addr, u_int8_t flags,
-			  struct ip_data *ipd);
+			  struct ip_data *ipd, u_int32_t grp_addr);
 void rreq_record_timeout(void *arg);
 struct blacklist *rreq_blacklist_insert(u_int32_t dest_addr);
 void rreq_blacklist_timeout(void *arg);
 void rreq_local_repair(rt_table_t * rt, u_int32_t src_addr,
 		       struct ip_data *ipd);
 
+#ifdef MAODV
+void NS_CLASS rreq_forward_uni(RREQ * rreq, u_int32_t dest, int ttl, int size);
+#endif /* MAODV */
+
 #ifdef NS_PORT
 struct rreq_record *rreq_record_insert(u_int32_t orig_addr, u_int32_t rreq_id);
 struct rreq_record *rreq_record_find(u_int32_t orig_addr, u_int32_t rreq_id);
 struct blacklist *rreq_blacklist_find(u_int32_t dest_addr);
 #endif				/* NS_PORT */
+
+int get_route_metric(u_int32_t dest_addr);
 
 #endif				/* NS_NO_DECLARATIONS */
 
diff -urNb aodv-uu-0.7.2/aodv_socket.c maodv-umd-0.7.2/aodv_socket.c
--- aodv-uu-0.7.2/aodv_socket.c	Wed Jun 18 15:41:38 2003
+++ maodv-umd-0.7.2/aodv_socket.c	Mon Jun 30 13:53:46 2003
@@ -43,6 +43,12 @@
 #ifdef USE_IW_SPY
 #include "link_qual.h"
 #endif
+
+#ifdef MAODV
+#include "maodv_mact.h"
+#include "maodv_grph.h"
+#endif
+
 #endif				/* NS_PORT */
 
 #ifndef NS_PORT
@@ -93,10 +99,11 @@
     }
 
     if (nleft == 1)
-	sum += *(unsigned char *) w;
+    sum += *(unsigned char*)w;
                                 
     sum = (sum >> 16) + (sum & 0xffff);
     sum += (sum >> 16);          
+
     return ~sum;
 
 }
@@ -209,6 +216,8 @@
     if ((aodv_msg->type == AODV_RREP && ttl == 1 && dst == AODV_BROADCAST)) {
 	hello_process((RREP *) aodv_msg, len, ifindex);
 	return;
+/*    } else if ( dst == AODV_BROADCAST ) {
+        bcast_process( src, ifindex ); */
     }
 
     /* Make sure we add/update neighbors */
@@ -233,6 +242,16 @@
 	DEBUG(LOG_DEBUG, 0, "Received RREP_ACK");
 	rrep_ack_process((RREP_ack *) aodv_msg, len, src, dst);
 	break;
+#ifdef MAODV
+    case MAODV_MACT:
+        DEBUG(LOG_DEBUG, 0, "Received MACT");
+        mact_process((MACT *) aodv_msg);
+        break;
+    case MAODV_GRPH:
+        DEBUG(LOG_DEBUG, 0, "Received GRPH");
+        grph_process((GRPH *) aodv_msg, src, ttl);
+        break;
+#endif
     default:
 	log(LOG_WARNING, 0, __FUNCTION__,
 	    "Unknown msg type %u rcvd from %s to %s", aodv_msg->type,
@@ -361,7 +380,7 @@
     ip = (struct iphdr *) send_buf;
     ip->version = IPVERSION;
     ip->ihl = sizeof(struct iphdr) >> 2;
-    ip->tos |= IPTOS_PREC_NETCONTROL | IPTOS_LOWDELAY; /* Highest priority */
+    ip->tos = IPTOS_PREC_NETCONTROL | IPTOS_LOWDELAY; /* Highest priority */
     ip->tot_len = htons(totlen);
     ip->id = 0; /* Let IP set */
     ip->frag_off = htons(0x4000); /* Set Do Not Fragment bit */
@@ -378,6 +397,7 @@
     udp->dest = htons(AODV_PORT);
     udp->len = htons(len + sizeof(struct udphdr));
     
+    udp->check = 0;
     udp->check = in_udp_csum(ip->saddr, ip->daddr, udp->len, 
 			     ip->protocol, (unsigned short *)udp);
 
diff -urNb aodv-uu-0.7.2/aodv_timeout.c maodv-umd-0.7.2/aodv_timeout.c
--- aodv-uu-0.7.2/aodv_timeout.c	Tue May 27 12:32:58 2003
+++ maodv-umd-0.7.2/aodv_timeout.c	Wed Jun 25 17:46:09 2003
@@ -42,6 +42,12 @@
 #include "seek_list.h"
 #include "icmp.h"
 
+#ifdef MAODV
+#include "multicast_routing_table.h"
+#include "maodv_mact.h"
+#include "maodv_neighbor.h"
+#endif /* MAODV */
+
 extern int expanding_ring_search, local_repair;
 void route_delete_timeout(void *arg);
 
@@ -54,6 +60,10 @@
     struct timeval now;
     seek_list_t *seek_entry;
     rt_table_t *rt, *repair_rt;
+#ifdef MAODV
+    u_int32_t dest_addr;
+#endif
+
     seek_entry = (seek_list_t *) arg;
 
 #define TTL_VALUE seek_entry->ttl
@@ -97,10 +107,76 @@
 	    (2 * NET_TRAVERSAL_TIME))
 	    rt_table_update_timeout(rt, 2 * NET_TRAVERSAL_TIME);
 
-	rreq_send(seek_entry->dest_addr, seek_entry->dest_seqno,
-		  TTL_VALUE, seek_entry->flags);
+        rreq_send_ext(seek_entry->dest_addr, seek_entry->dest_seqno,
+            seek_entry->ttl, seek_entry->flags, seek_entry->grp_hcnt,
+            seek_entry->grp_addr);
+    } else {
+#ifdef MAODV
+        if(seek_entry->flags & RREQ_JOIN && !(seek_entry->flags & RREQ_REPAIR)) {
+            mrt_table_t *group_rec;
+            mrt_nexthop_t *upstream;
+
+            DEBUG(LOG_DEBUG, 0, "In special MCAST timeout segment");
+
+            /* try to join the group */
+            group_rec = mrt_table_find(seek_entry->dest_addr);
+            upstream = mact_activate_best_upstream(group_rec);
+
+            if(upstream) {
+                if(group_rec->is_broken) {
+                    /* we were repairing route */
+                    group_rec->is_broken = 0;
+                } else if(group_rec->is_gateway) {
+                    /* Gateway joining, not a member */
+                } else {
+                    /* we were able to select an upstream */
+                    group_rec->is_member = 1;
+                    DEBUG(LOG_DEBUG, 0, "Joined Group");
+                }
+            } else {
+                /* have to become leader ourselves */
+                if(group_rec->is_broken && !group_rec->is_member) {
+                    /* we are a router who lost his upstream */
+                    group_rec->is_broken = 0;
+                    mact_make_downstream_leader(group_rec);
+                    DEBUG(LOG_DEBUG, 0, "Link broke, make downstream leader.");
+                } else {
+                    if(group_rec->is_broken) {
+                        group_rec->is_broken = 0;
+                        DEBUG(LOG_DEBUG, 0, "Was broken, now fixed.");
+                    }
 
+                    mrt_table_become_leader(group_rec);
+                    DEBUG(LOG_DEBUG, 0, "Became group leader");
+                }
+            }
+
+            dest_addr = seek_entry->dest_addr;
+            if(seek_list_remove(seek_list_find(seek_entry->dest_addr))) {
+                if(mcast_packet_queue_send(dest_addr) < 0) {
+                    DEBUG(LOG_DEBUG, 0, "Error dequeueing packets.");
+                }
     } else {
+                DEBUG(LOG_DEBUG, 0, "No longer in seek list.");
+            }
+
+            return;
+        } else if((seek_entry->flags & RREQ_JOIN) &&
+                (seek_entry->flags & RREQ_REPAIR)) {
+            mrt_table_t *mrt;
+            mrt = mrt_table_find(seek_entry->grp_addr);
+
+            if(mrt) {
+                /* Done merging, might have worked. */
+                DEBUG(LOG_DEBUG, 0, "Route discovery for merge timed out. Clearing in_repair.");
+                mrt->in_repair = 0;
+
+            } else {
+                DEBUG(LOG_DEBUG, 0, "Bad dest_addr:%d in seek_list.",
+                        ip_to_str(seek_entry->grp_addr));
+            }
+        }
+#endif /* MAODV */
 	packet_queue_drop(seek_entry->dest_addr);
 
 	DEBUG(LOG_DEBUG, 0, "NO ROUTE FOUND!");
@@ -113,7 +189,7 @@
 #endif
 	repair_rt = rt_table_find(seek_entry->dest_addr);
 
-	seek_list_remove(seek_entry);
+	seek_list_remove(seek_list_find(seek_entry->dest_addr));
 
 	/* If this route has been in repair, then we should timeout
 	   the route at this point. */
@@ -173,6 +249,31 @@
     precursor_list_destroy(rt);
 }
 
+#ifdef MAODV
+void NS_CLASS multicast_route_expire_timeout( void * arg )
+{
+    mrt_table_t *mrt;
+
+    mrt = (mrt_table_t *) arg;
+
+    if ( !mrt ) {
+        log( LOG_WARNING, 0, __FUNCTION__, "arg was NULL, ignoring timeout!" );
+        return;
+    }
+
+    DEBUG( LOG_DEBUG, 0, "Multicast Route %s DOWN, seqno = %d",
+        ip_to_str( mrt->grp_addr ), mrt->grp_seqno );
+
+/*
+    CHECK: Remove after creating valid flag.
+
+    mrt_table_invalidate( mrt );
+    mrt_nexthop_remove_all( mrt );
+*/
+
+    return;
+}
+#endif
 
 void NS_CLASS route_expire_timeout(void *arg)
 {
@@ -242,6 +343,9 @@
 #endif
 	}
 	neighbor_link_break(rt);
+#ifdef MAODV
+        mcast_neighbor_link_break(rt);
+#endif
     }
 }
 
diff -urNb aodv-uu-0.7.2/aodv_timeout.h maodv-umd-0.7.2/aodv_timeout.h
--- aodv-uu-0.7.2/aodv_timeout.h	Thu May 22 19:11:35 2003
+++ maodv-umd-0.7.2/aodv_timeout.h	Wed Jun 25 17:46:09 2003
@@ -31,6 +31,7 @@
 void route_delete_timeout(void *arg);
 void local_repair_timeout(void *arg);
 void route_discovery_timeout(void *arg);
+void multicast_route_expire_timeout(void *arg);
 void route_expire_timeout(void *arg);
 void hello_timeout(void *arg);
 void rrep_ack_timeout(void *arg);
diff -urNb aodv-uu-0.7.2/defs.h maodv-umd-0.7.2/defs.h
--- aodv-uu-0.7.2/defs.h	Mon Jun  9 06:43:40 2003
+++ maodv-umd-0.7.2/defs.h	Wed Jun 25 17:46:09 2003
@@ -27,13 +27,16 @@
 #include <unistd.h>
 #include <sys/time.h>
 #include <sys/types.h>
+#include <sys/socket.h>
 
 #ifndef NS_PORT
 #include <sys/signal.h>
+
 #include <netinet/in.h>
 #include <arpa/inet.h>
 #include <netinet/ip.h>
 #include <sys/ioctl.h>
+
 #endif
 
 #include <syslog.h>
@@ -94,6 +97,9 @@
     u_int32_t ipaddr;		/* The local IP address */
     u_int32_t netmask;		/* The netmask we use */
     u_int32_t broadcast;
+#ifdef MAODV
+    int injectfd;       /* Handle to IP injection device for this interface */
+#endif
 };
 
 struct host_info {
@@ -161,7 +167,6 @@
 
 #endif
 
-
 /* Two macros to simplify retriving of a dev_info struct. Either using
    an ifindex or a device number (index into devs array). */
 #define DEV_IFINDEX(ifindex) (this_host.devs[ifindex2devindex(ifindex)])
@@ -179,6 +184,12 @@
 #define AODV_RERR     3
 #define AODV_RREP_ACK 4
 
+#ifdef MAODV
+/* multicast types */
+#define MAODV_MACT    5
+#define MAODV_GRPH    6
+#endif /* MAODV */
+
 /* A generic AODV packet header struct... */
 #ifdef NS_PORT
 struct AODV_msg {
@@ -211,6 +222,13 @@
 #define RREQ_EXT 2
 #define RREP_EXT 2
 #define RREP_HELLO_NEIGHBOR_SET_EXT 3
+
+#ifdef MAODV
+/* MAODV Extension types */
+#define RREQ_GRP_REBUILD_EXT 4
+#define RREQ_GRP_MERGE_EXT 9
+#define RREP_GRP_MERGE_EXT 9
+#endif /* MAODV */
 
 /* An generic AODV extensions header */
 typedef struct {
diff -urNb aodv-uu-0.7.2/icmp.c maodv-umd-0.7.2/icmp.c
--- aodv-uu-0.7.2/icmp.c	Mon Oct  7 11:42:20 2002
+++ maodv-umd-0.7.2/icmp.c	Wed Jun 25 17:46:09 2003
@@ -33,7 +33,12 @@
 char icmp_send_buf[ICMP_BUFSIZE];
 int icmp_socket;
 
+/* Used in igmp.c's IGMP injection function */
+#ifdef MAODV
+unsigned short cksum(unsigned short *w, int len)
+#else
 static unsigned short cksum(unsigned short *w, int len)
+#endif
 {
     int sum = 0;
     unsigned short answer = 0;
diff -urNb aodv-uu-0.7.2/icmp.h maodv-umd-0.7.2/icmp.h
--- aodv-uu-0.7.2/icmp.h	Wed Jun 19 10:46:31 2002
+++ maodv-umd-0.7.2/icmp.h	Wed Jun 25 17:46:09 2003
@@ -24,5 +24,9 @@
 
 void icmp_init();
 int icmp_send_host_unreachable(char *data, int len);
+#ifdef MAODV
+/* MAODV packet injection needs an IP checksum function */
+unsigned short cksum(unsigned short *w, int len);
+#endif /* MAODV */
 
 #endif
diff -urNb aodv-uu-0.7.2/igmp.c maodv-umd-0.7.2/igmp.c
--- aodv-uu-0.7.2/igmp.c	Wed Dec 31 19:00:00 1969
+++ maodv-umd-0.7.2/igmp.c	Mon Jun 30 16:00:00 2003
@@ -0,0 +1,218 @@
+#ifdef MAODV
+
+/*****************************************************************************
+ *
+ * Copyright (C) 2003 CSHCN, University of Maryland.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Authors: Dionysus Blazakis <dblaze@umd.edu>
+ *          Jonathan Polley <jpolley@umd.edu>
+ *          Dan Rusk <drusk@umd.edu>
+ *          Manish Karir <karir@umd.edu>
+ *          Jonathan McGee <mcgee@umd.edu>
+ *
+ *****************************************************************************/
+
+#ifdef NS_PORT
+#include "aodv-uu.h"
+#else
+#include <netinet/in.h>
+#include "aodv_socket.h"
+#include "params.h"
+#include "seek_list.h"
+#include "defs.h"
+#include "debug.h"
+#include "multicast_routing_table.h"
+#include "igmp.h"
+#include "icmp.h"
+#include "aodv_rreq.h"
+#include "maodv_mact.h"
+#include "packet_queue.h"
+#endif
+
+static void maodv_join(u_int32_t grp_addr){
+    mrt_table_t *group_rec;
+
+    group_rec=mrt_table_find(grp_addr);
+
+    if(group_rec==NULL){
+        group_rec=mrt_table_insert(grp_addr, 0, 0, 0, 255, 0);
+    }
+   
+    if(group_rec->is_gateway) {
+        /* Gateway code has joined or is in the process of doing so */
+        group_rec->is_member = 1;
+    } else if(!group_rec->is_router){
+        /* no route to group, so let's find one. */
+        rreq_route_discovery(grp_addr, RREQ_JOIN, NULL, 0);
+    }else if(!group_rec->is_member){
+        /* I'm routing, so I just need to reactivate my membership */
+        group_rec->is_member=1;
+    }
+}
+
+static void maodv_leave(u_int32_t grp_addr){
+    mrt_table_t *group_rec;
+
+    group_rec=mrt_table_find(grp_addr);
+    
+    /* don't leave if not in the group */
+    if(group_rec==NULL || !group_rec->is_router)
+        return;
+
+    /* leave group */
+    group_rec->is_member=0;
+
+    /* If gateway mode is enabled, make sure the gateway flag is set */
+    if(this_host.gateway_mode) {
+        group_rec->is_gateway = 1;
+    }
+
+    if(group_rec->is_gateway) {
+        /* Only prune if no up or down stream */
+        if((group_rec->activated_downstream_cnt == 0)
+                && (group_rec->activated_upstream_cnt == 0)) {
+            group_rec->am_leader = 0;
+            group_rec->is_gateway = 0;
+            mrt_table_stop_routing(group_rec);
+
+            /* remove any pending RREQs (or other packets) for this group */
+            seek_list_remove(seek_list_find(grp_addr));
+            packet_queue_drop(grp_addr);
+
+            /* flush all nexthops */
+            mrt_nexthop_remove_all(group_rec);
+        }
+    } else if(group_rec->am_leader){
+        if(group_rec->activated_downstream_cnt>0){
+            /* do have downstreams, so make one new leader */
+            mact_make_downstream_leader(group_rec);
+        }
+        group_rec->am_leader=0;
+        mrt_table_stop_routing(group_rec);
+    }else if(group_rec->activated_downstream_cnt==0){
+        /* no downs, prune self and invalidate route */
+        mrt_nexthop_t *upstream;
+
+        upstream=mrt_table_get_activated_upstream(group_rec);
+        if(upstream != NULL){
+            mact_send(MACT_PRUNE, 1, grp_addr, upstream->addr,1);
+            mrt_nexthop_deactivate(group_rec, upstream->addr);
+        }
+        mrt_table_stop_routing(group_rec);
+
+        /* remove any pending RREQs (or other packets) for this group */
+        seek_list_remove(seek_list_find(grp_addr));
+        packet_queue_drop(grp_addr);
+
+        /* flush all nexthops */
+        mrt_nexthop_remove_all(group_rec);
+    }
+    /* otherwise I must keep route valid so I keep routing */
+}
+
+static void maodv_query(IGMP* pkt, int ifindex) {
+    mrt_table_t *tblentry;
+    int n;
+
+    /* Iterate through all the multicast routing entries */
+    for(n = 0; n < MRT_TABLESIZE; n++) {
+        tblentry = mrt_tbl.tbl[n];
+
+        while(tblentry) {
+            igmp_sendreply(tblentry, ifindex);
+            tblentry = tblentry->next;
+        }
+    }
+}
+
+void igmp_process( IGMP *pkt, int ifindex )
+{
+    u_int32_t grp_addr;
+    DEBUG(LOG_DEBUG, 0, "IGMP packet out. Dropped.");
+
+    grp_addr=ntohl(pkt->igmp_group.s_addr);
+
+    switch( pkt->igmp_type ) {
+        case IGMP_V1_MEMBERSHIP_REPORT:
+        case IGMP_V2_MEMBERSHIP_REPORT:
+            DEBUG(LOG_DEBUG, 0, "IGMP_REPORT");
+
+            /* may not do anything if we already have a valid route. */
+            maodv_join( grp_addr ); 
+
+            break;
+        case IGMP_V2_LEAVE_GROUP:
+            DEBUG(LOG_DEBUG, 0, "IGMP_LEAVE");
+
+            /* it may not actually prune, but at least un-member me. */
+            maodv_leave( grp_addr ); 
+
+            break;
+        case IGMP_MEMBERSHIP_QUERY:
+            DEBUG(LOG_DEBUG, 0, "IGMP_QUERY");
+
+            /* Terrestrial multicast router is asking for list of groups */
+            maodv_query( pkt, ifindex );
+
+            break;
+        default:
+            DEBUG(LOG_DEBUG, 0, "IGMP_UNKNOWN [0x%x]", pkt->igmp_type );
+            break;
+    }
+}
+
+void igmp_sendreply(mrt_table_t* mrt, int ifindex) {
+    char szBuffer[sizeof(struct iphdr) + sizeof(struct igmphdr)];
+    struct iphdr* ip = (struct iphdr*)szBuffer;
+    struct igmphdr* igmp = (struct igmphdr*)(szBuffer + sizeof(struct iphdr));
+    int injectfd = DEV_IFINDEX(ifindex).injectfd, err;
+
+    if(!mrt->nexthops || !mrt->is_router) {
+        /* Nobody listening, so don't send */
+        return;
+    }
+
+    if(injectfd != -1) {
+        ip->version = IPVERSION;
+        ip->ihl = sizeof(struct iphdr) >> 2;
+        ip->tos = 0;
+        ip->tot_len = htons(sizeof(szBuffer));
+        ip->id = 1;
+        ip->frag_off = 0;
+        ip->ttl = 1;
+        ip->protocol = IPPROTO_IGMP;
+        ip->saddr = htonl(mrt->nexthops->addr);
+        ip->daddr = htonl(mrt->grp_addr);
+        ip->check = 0;
+        ip->check = cksum((unsigned short*)ip, sizeof(struct iphdr));
+        igmp->type = IGMP_V1_MEMBERSHIP_REPORT;
+        igmp->code = 0;
+        igmp->group = ip->daddr;
+        igmp->csum = 0;
+        igmp->csum = cksum((unsigned short*)igmp, sizeof(struct igmphdr));
+
+        DEBUG(LOG_DEBUG, 0, "Injecting IGMP REPORT for %s from %s on %s",
+            ip_to_str(ntohl(ip->daddr)), ip_to_str(ntohl(ip->saddr)),
+            DEV_IFINDEX(ifindex).ifname);
+        err = write(injectfd, szBuffer, sizeof(szBuffer));
+        if(err < sizeof(szBuffer)) {
+            perror("write");
+        }
+    }
+}
+
+#endif /* MAODV */
diff -urNb aodv-uu-0.7.2/igmp.h maodv-umd-0.7.2/igmp.h
--- aodv-uu-0.7.2/igmp.h	Wed Dec 31 19:00:00 1969
+++ maodv-umd-0.7.2/igmp.h	Wed Jun 25 17:46:09 2003
@@ -0,0 +1,47 @@
+/*****************************************************************************
+ *
+ * Copyright (C) 2003 CSHCN, University of Maryland.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Authors: Dionysus Blazakis <dblaze@umd.edu>
+ *          Jonathan Polley <jpolley@umd.edu>
+ *          Dan Rusk <drusk@umd.edu>
+ *          Manish Karir <karir@umd.edu>
+ *          Jonathan McGee <mcgee@umd.edu>
+ *
+ *****************************************************************************/
+
+#ifndef IGMP_H
+#define IGMP_H
+
+#ifndef NS_NO_GLOBALS
+
+#include "defs.h"
+#include "multicast_routing_table.h"
+#include <netinet/igmp.h>
+
+#define IGMP    struct igmp
+
+#endif				/* NS_NO_GLOBALS */
+
+#ifndef NS_NO_DECLARATIONS
+
+void igmp_process( IGMP * buff, int ifindex );
+void igmp_sendreply( mrt_table_t * mrt, int ifindex );
+
+#endif				/* NS_NO_DECLARATIONS */
+
+#endif				/* IGMP_H */
diff -urNb aodv-uu-0.7.2/k_mroute.c maodv-umd-0.7.2/k_mroute.c
--- aodv-uu-0.7.2/k_mroute.c	Wed Dec 31 19:00:00 1969
+++ maodv-umd-0.7.2/k_mroute.c	Thu Jul 17 18:03:42 2003
@@ -0,0 +1,239 @@
+#ifdef MAODV
+
+/*****************************************************************************
+ *
+ * Copyright (C) 2003 CSHCN, University of Maryland.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Authors: Dionysus Blazakis <dblaze@umd.edu>
+ *          Jonathan Polley <jpolley@umd.edu>
+ *          Dan Rusk <drusk@umd.edu>
+ *          Manish Karir <karir@umd.edu>
+ *
+ *****************************************************************************/
+
+#include "k_mroute.h"
+#include <stdio.h>    /* perror */
+#include <unistd.h>
+#include <sys/socket.h>
+#include <linux/in.h>
+#include <linux/mroute.h>
+#include <string.h>
+
+/* Yanked from debug.h during a battle with the includes. */
+#include <sys/syslog.h>
+void log(int, int, const char *, char *, ...);
+
+int multicast_socket = -1;
+
+/* much of this code was taken from Dinesh's kernel MAODV
+   implementation and cleaned up for user space.
+
+   also, smc_route v.0.92 provided a good user space reference. */
+
+/*
+ *  kernel_mrt_init( )
+ *  Create and initialize the multicast socket for communication with the kernel.
+ */
+int kernel_mrt_init( void )
+{
+    int error;
+    int enable = 1;
+
+    multicast_socket = socket( AF_INET, SOCK_RAW, IPPROTO_IGMP );
+
+    /* error creating socket? */
+    if ( multicast_socket < 0 ) {
+        log(LOG_WARNING, 0, __FUNCTION__,
+            "Failed to create socket.");
+        return -1;
+    }
+
+    error = setsockopt( multicast_socket, IPPROTO_IP, MRT_INIT, 
+        (int *) &enable, sizeof( enable ) );
+    if ( error < 0 ) {
+        log(LOG_WARNING, 0, __FUNCTION__,
+            "Error starting kernel multicast routing.");
+        return -1;
+    }
+
+    log(LOG_DEBUG, 0, __FUNCTION__,
+        "Got the multicast kernel route socket!");
+    
+    return 0;
+}
+
+/*
+ *  kernel_mrt_clean_up( )
+ *  Close the socket and clean up the virtual interfaces.
+ */
+int kernel_mrt_clean_up( void )
+{
+    if(multicast_socket != -1) {
+
+    int error = setsockopt( multicast_socket, IPPROTO_IP, MRT_DONE, 
+        (char *) NULL, 0 );
+    if ( error < 0 ) {
+        log(LOG_WARNING, 0, __FUNCTION__,
+            "Error finishing (MRT_DONE) kernel multicast routing.");
+        return -1;
+    }
+
+    close( multicast_socket );
+
+    log(LOG_DEBUG, 0, __FUNCTION__,
+       "Killed multicast socket!");
+
+    } /* if(multicast_socket != -1) { */
+    return 0;
+}
+
+/*
+ *  kernel_mrt_vif_add( addr, index )
+ *  Adds a virtual interface from ip "addr" as index "index".
+ */
+int kernel_mrt_vif_add( u_int32_t this_ip, int index )
+{
+    if(multicast_socket != -1) {
+
+    struct vifctl vc;
+    int error;
+
+    /* taken from smcroute-0.92 */
+    vc.vifc_vifi = index;
+    vc.vifc_flags = 0;
+    vc.vifc_threshold = 1;
+    vc.vifc_rate_limit = 0;
+                
+    vc.vifc_lcl_addr.s_addr = htonl(this_ip);
+    vc.vifc_rmt_addr.s_addr = INADDR_ANY;
+
+    error = setsockopt( multicast_socket, IPPROTO_IP, MRT_ADD_VIF, 
+        (char *)&vc, sizeof(vc) ); 
+    if ( error < 0 ) {
+        perror("ERROR! " );
+        log(LOG_WARNING, 0, __FUNCTION__,
+            "Error creating virtual interface for kernel multicast routing[%d]." , error );
+        return -1;
+    }
+
+    log(LOG_DEBUG, 0, __FUNCTION__,
+        "Added virtual interface.");
+
+    } /* if(multicast_socket != -1) { */
+   return 0; 
+}
+
+/*
+ *  kernel_mrt_vif_del( addr, index )
+ *  Deletes a virtual interface at  from ip "addr" as index "index".
+ */
+int kernel_mrt_vif_del( u_int32_t this_ip, int index )
+{
+    if(multicast_socket != -1) {
+
+    struct vifctl vc;
+    int error;
+
+    vc.vifc_vifi = (vifi_t) index;
+    vc.vifc_flags = 0;
+    // Is the threshold value 0 or 1??? - Dinesh
+    vc.vifc_threshold = 0;
+    vc.vifc_rate_limit = 0;
+                
+    vc.vifc_lcl_addr.s_addr = htonl(this_ip);
+    vc.vifc_rmt_addr.s_addr = INADDR_ANY;
+
+    error = setsockopt( multicast_socket, IPPROTO_IP, MRT_DEL_VIF, 
+        (char *)&vc, sizeof(vc) ); 
+    if ( error < 0 ) {
+        log(LOG_WARNING, 0, __FUNCTION__,
+            "Error deleting virtual interface for kernel multicast routing.");
+        return -1;
+    }
+
+    } /* if(multicast_socket != -1) { */
+    return 0; 
+}
+
+/*
+ *  kernel_mrt_add_route( source, grp, vif )
+ *  Add a multicast route to the kernel routing cache.
+ */
+int kernel_mrt_add_route( u_int32_t src, u_int32_t grp, int index )
+{
+    if(multicast_socket != -1) {
+
+    struct mfcctl mc;
+    int error;
+
+    mc.mfcc_origin.s_addr = htonl(src);
+    mc.mfcc_mcastgrp.s_addr = htonl(grp);
+    mc.mfcc_parent = (vifi_t) index;
+    memset(mc.mfcc_ttls, 0, sizeof(mc.mfcc_ttls));
+    mc.mfcc_ttls[index] = 2;  /* CHECK: this seems odd... */
+
+    error = setsockopt( multicast_socket, IPPROTO_IP, MRT_ADD_MFC, 
+        (char *) ( &mc ), sizeof( mc ) );
+
+    if ( error < 0 ) {
+        perror( "ERROR " );
+        log(LOG_WARNING, 0, __FUNCTION__,
+            "Error adding route for kernel multicast routing.");
+        return -1;
+    }
+
+    log(LOG_DEBUG, 0, __FUNCTION__,
+        "Added multicast route cache entry.");
+ 
+    } /* if(multicast_socket != -1) { */
+    return 0;
+}
+
+/*
+ *  kernel_mrt_del_route( source, grp, vif )
+ *  Delete a multicast route from the kernel routing cache.
+ */
+int kernel_mrt_del_route( u_int32_t src, u_int32_t grp, int index )
+{
+    if(multicast_socket != -1) {
+
+    struct mfcctl mc;
+    int error;
+
+    /* CHECK: ttls are diff in Dinesh's code... intentional? */
+    mc.mfcc_origin.s_addr = htonl(src);
+    mc.mfcc_mcastgrp.s_addr = htonl(grp);
+    mc.mfcc_parent = (vifi_t) index;
+    mc.mfcc_ttls[index] = 1;
+
+    error = setsockopt( multicast_socket, IPPROTO_IP, MRT_DEL_MFC, 
+        (char *) ( &mc ), sizeof( struct mfcctl ) );
+
+    if ( error < 0 ) {
+        log(LOG_WARNING, 0, __FUNCTION__,
+            "Error deleting route for kernel multicast routing.");
+        return -1;
+    }
+
+    log(LOG_DEBUG, 0, __FUNCTION__,
+        "Removed multicast route cache entry.");
+ 
+    } /* if(multicast_socket != -1) { */
+    return 0;
+}
+
+#endif /* MAODV */
diff -urNb aodv-uu-0.7.2/k_mroute.h maodv-umd-0.7.2/k_mroute.h
--- aodv-uu-0.7.2/k_mroute.h	Wed Dec 31 19:00:00 1969
+++ maodv-umd-0.7.2/k_mroute.h	Wed Jun 25 17:46:09 2003
@@ -0,0 +1,38 @@
+/*****************************************************************************
+ *
+ * Copyright (C) 2003 CSHCN, University of Maryland.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Authors: Dionysus Blazakis <dblaze@umd.edu>
+ *          Jonathan Polley <jpolley@umd.edu>
+ *          Dan Rusk <drusk@umd.edu>
+ *          Manish Karir <karir@umd.edu>
+ *
+ *****************************************************************************/
+
+#ifndef K_MROUTE_H
+#define K_MROUTE_H
+
+#include <sys/socket.h>
+
+int kernel_mrt_init( void );
+int kernel_mrt_clean_up( void );
+int kernel_mrt_vif_add( u_int32_t this_ip, int index );
+int kernel_mrt_vif_del( u_int32_t this_ip, int index );
+int kernel_mrt_add_route( u_int32_t src, u_int32_t grp, int index );
+int kernel_mrt_del_route( u_int32_t src, u_int32_t grp, int index );
+
+#endif /* K_MROUTE_H */
diff -urNb aodv-uu-0.7.2/kaodv.c maodv-umd-0.7.2/kaodv.c
--- aodv-uu-0.7.2/kaodv.c	Wed Nov  6 08:48:46 2002
+++ maodv-umd-0.7.2/kaodv.c	Fri Dec  5 17:42:32 2003
@@ -117,6 +117,12 @@
     /* Check which hook the packet is on... */
     switch (hooknum) {
     case NF_IP_PRE_ROUTING:
+#ifdef MAODV
+    /* Pass incoming IGMP (since MAODV might have generated it) */
+    if((*skb)->nh.iph->protocol == IPPROTO_IGMP) {
+        break;
+    }
+#endif
 	/* Loop through all AODV enabled interfaces and see if the packet
 	 * is bound to any of them. */
 	for (i = 0; i < nif; i++)
@@ -124,7 +130,12 @@
 		(*skb)->nfmark = 3;
 		goto queue;
 	    }
-	break;
+
+    /* Gateway mode requirement */
+    (*skb)->nfmark = 4;
+    goto queue;
+    goto accept;
+
     case NF_IP_LOCAL_OUT:
 	for (i = 0; i < nif; i++)
 	    if (ifindices[i] == out->ifindex) {
@@ -132,6 +143,7 @@
 		goto queue;
 	    }
 	break;
+
     case NF_IP_POST_ROUTING:
 	/* Re-route all packets before sending on interface. This will
 	   make sure queued packets are routed on a newly installed
diff -urNb aodv-uu-0.7.2/kinject.c maodv-umd-0.7.2/kinject.c
--- aodv-uu-0.7.2/kinject.c	Wed Dec 31 19:00:00 1969
+++ maodv-umd-0.7.2/kinject.c	Thu Jul 17 18:03:45 2003
@@ -0,0 +1,280 @@
+/*****************************************************************************
+ *
+ * Copyright (C) 2003 CSHCN, University of Maryland.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Authors: Jonathan McGee <mcgee@umd.edu>
+ *
+ *****************************************************************************/
+#include <linux/config.h>
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/notifier.h>
+#include <asm/atomic.h>
+
+#define CONFIG_PROC_FS
+#include <linux/proc_fs.h>
+
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <net/ip.h>
+
+/* Root for our network output entries */
+static struct proc_dir_entry *proc_netwrite = NULL;
+
+/* Linked list of installed proc entries */
+struct proc_netwrite_entry {
+    struct proc_netwrite_entry *next;
+    struct proc_dir_entry *entry;
+    const char *devname;
+    struct net_device *dev;
+};
+
+static struct proc_netwrite_entry *proc_netwrite_entries = NULL;
+
+/*
+ * Injecting packets into the IP stack
+ */
+static int proc_netwrite_write(struct file *file, const char *buffer,
+        unsigned long count, void *data) {
+    struct sk_buff *skb = NULL;
+    struct iphdr *ip = (struct iphdr*)buffer;
+    struct net_device *dev = NULL;
+
+    /* Do some sanity checking */
+    if(data == NULL) {
+        printk(KERN_INFO __FILE__ ": %ld bytes written but no output "
+                "device!\n", count);
+        return -EPIPE;
+    }
+
+    /* Check data for basic sanity */
+    if((count < sizeof(struct iphdr)) || (ip->version != 4)
+            || (count > 0xFFFF)) {
+        printk(KERN_INFO __FILE__ ": Packet so illegal, it's gonna be "
+                "ignored.\n");
+        return -EIO;
+    }
+
+    /* Get our device */
+    dev = ((struct proc_netwrite_entry*)data)->dev;
+    if(dev == NULL) {
+        printk(KERN_DEBUG __FILE__ ": Odd, lost the output device.\n");
+        return -EPIPE;
+    }
+
+    /* Make sure it's up */
+    if(!netif_running(dev)) {
+        printk(KERN_INFO __FILE__ ": Packet sent to down device %s\n",
+                dev->name);
+        return -EIO;
+    }
+
+    /* Create packet for sending */
+    skb = dev_alloc_skb(count);
+    if(skb == NULL) {
+        printk(KERN_INFO __FILE__ ": Out of memory, cannot create sk_buff\n");
+        return -ENOMEM;
+    }
+
+    /* Initialize data structure as necessary */
+    ip = (struct iphdr*)skb_put(skb, count);
+    memcpy(ip, buffer, count);
+
+    skb->h.raw = NULL;
+    skb->nh.iph = ip;
+    skb->mac.raw = NULL;
+
+    skb->pkt_type = PACKET_HOST;
+    skb->protocol = __constant_htons(ETH_P_IP);
+    skb->dev = dev;
+
+    skb->ip_summed = CHECKSUM_NONE;
+    skb->len = count;
+    do_gettimeofday(&skb->stamp);
+
+    /* "Receive" data */
+    printk(KERN_DEBUG __FILE__ ": Feeding a %ld byte packet into the stack\n",
+            count);
+    ip_rcv(skb, skb->dev, NULL);
+    return count;
+}
+
+/*
+ * List behavior
+ */
+
+/* Add an item to the list */
+static int proc_netwrite_addentry(struct net_device *dev) {
+    struct proc_netwrite_entry *newentry;
+    struct proc_dir_entry *newprocentry;
+
+    /* Attempt to create proc entry */
+    newprocentry = create_proc_entry(dev->name, S_IFREG|S_IRUGO|S_IWUSR,
+            proc_netwrite);
+    if(newprocentry == NULL) {
+        return 1;
+    }
+
+    /* Allocate memory for data structure */
+    newentry = kmalloc(sizeof(struct proc_netwrite_entry), GFP_ATOMIC);
+    if(newentry == NULL) {
+        remove_proc_entry(dev->name, proc_netwrite);
+        return 1;
+    }
+
+    /* Initialize */
+    newentry->next = NULL;
+    newentry->entry = newprocentry;
+    newentry->devname = dev->name;
+    newentry->dev = dev;
+    newprocentry->data = newentry;
+    newprocentry->write_proc = proc_netwrite_write;
+
+    /* Add to list */
+    if(proc_netwrite_entries == NULL) {
+        /* Empty list */
+        proc_netwrite_entries = newentry;
+    } else {
+        /* Find end of list and link in */
+        struct proc_netwrite_entry *head = proc_netwrite_entries;
+        for(; head->next; head = head->next);
+        head->next = newentry;
+    }
+
+    return 0;
+}
+
+/* Add all currently installed net devices to the list */
+static int proc_netwrite_addallentries() {
+    int err, errall = 0;
+    struct net_device *curr = dev_base;
+
+    while(curr) {
+        err = proc_netwrite_addentry(curr);
+        curr = curr->next;
+        if(err) {
+            errall = err;
+        }
+    }
+
+    return errall;
+}
+
+/* Remove from list */
+static int proc_netwrite_removeentry(struct net_device *dev) {
+    struct proc_netwrite_entry *prev, *curr;
+
+    /* Locate entry in list */
+    prev = NULL;
+    curr = proc_netwrite_entries;
+    while(curr && (curr->dev != dev)) {
+        prev = curr;
+        curr = curr->next;
+    }
+
+    /* If we found it, remove it */
+    if(curr) {
+        /* Remove from list */
+        if(prev) {
+            prev->next = curr->next;
+        } else {
+            proc_netwrite_entries = curr->next;
+        }
+        /* Remove proc entry */
+        curr->entry->data = NULL;
+        remove_proc_entry(curr->devname, proc_netwrite);
+        /* Clear it out in case proc file still open */
+        curr->dev = NULL;
+        curr->devname = NULL;
+        kfree(curr);
+    }
+
+    return 0;
+}
+
+/* Remove all entries in the list */
+static int proc_netwrite_removeallentries() {
+    while(proc_netwrite_entries != NULL) {
+        proc_netwrite_removeentry(proc_netwrite_entries->dev);
+    }
+
+    return 0;
+}
+
+/*
+ * Keep our /proc up to date with network devices
+ */
+int on_device_notify(struct notifier_block *self, unsigned long event, void *v) {
+    struct net_device *dev = (struct net_device*)v;
+    switch(event) {
+    case NETDEV_REGISTER:
+        /* New device added to kernel */
+        proc_netwrite_addentry(dev);
+        break;
+
+    case NETDEV_UNREGISTER:
+        /* Device being removed from kernel */
+        proc_netwrite_removeentry(dev);
+        break;
+    }
+    return NOTIFY_DONE;
+}
+
+struct notifier_block device_event_notifier = {
+    on_device_notify,
+    NULL,
+    0
+};
+
+/*
+ * Called when the module is inserted in the kernel.
+ */
+int init_module()
+{
+    /* Create directory to hold our nodes */
+    proc_netwrite = proc_mkdir("inject", proc_net);
+    if(proc_netwrite == NULL) {
+        /* Return failure if couldn't create the node */
+        return 1;
+    }
+    /* Create the nodes for currently installed devices */
+    proc_netwrite_addallentries();
+    /* Be notified on device changes */
+    register_netdevice_notifier(&device_event_notifier);
+    return 0;
+}
+
+/*
+ * Called when removing the module from memory... 
+ */
+void cleanup_module()
+{
+    /* Deregister entry into device notification */
+    unregister_netdevice_notifier(&device_event_notifier);
+    /* Remove existing devices */
+    proc_netwrite_removeallentries();
+    /* Remove node directory */
+    remove_proc_entry("inject", proc_net);
+}
+
+MODULE_DESCRIPTION("MAODV Gateway kernel support.");
+MODULE_AUTHOR("Jonathan McGee");
+#ifdef MODULE_LICENSE
+MODULE_LICENSE("GPL");
+#endif
diff -urNb aodv-uu-0.7.2/main.c maodv-umd-0.7.2/main.c
--- aodv-uu-0.7.2/main.c	Tue May 27 12:32:58 2003
+++ maodv-umd-0.7.2/main.c	Mon Jun 30 13:53:46 2003
@@ -43,6 +43,11 @@
 #include "aodv_hello.h"
 #include "packet_input.h"
 #include "packet_queue.h"
+#ifdef MAODV
+#include "multicast_routing_table.h"
+#include "multicast_packet_cache.h"
+#include "k_mroute.h"
+#endif
 
 #ifdef USE_IW_SPY
 #include "link_qual.h"
@@ -59,7 +64,7 @@
 int receive_n_hellos = 0;
 int hello_jittering = 1;
 int optimized_hellos = 0;
-int ratelimit = 1;		/* Option for rate limiting RREQs and RERRs. */
+int ratelimit = 0;		 /* Option for rate limiting RREQs and RERRs. */
 char *progname;
 int wait_on_reboot = 1;
 int hello_qual_threshold = 12;
@@ -191,36 +196,6 @@
     return 0;
 }
 
-int find_default_gw(void)
-{
-    FILE *route;
-    char buf[100], *l;
-
-    route = fopen("/proc/net/route", "r");
-
-    if (route == NULL) {
-	perror("open /proc/net/route");
-	exit(-1);
-    }
-
-    while (fgets(buf, sizeof(buf), route)) {
-	l = strtok(buf, " \t");
-	l = strtok(NULL, " \t");
-	if (l != NULL) {
-	    if (strcmp("00000000", l) == 0) {
-		l = strtok(NULL, " \t");
-		l = strtok(NULL, " \t");
-		if (strcmp("0003", l) == 0) {
-		    fclose(route);
-		    return 1;
-		}
-	    }
-	}
-    }
-    fclose(route);
-    return 0;
-}
-
 /*
  * Returns information on a network interface given its name...
  */
@@ -293,6 +268,17 @@
 	sprintf(buf, "/sbin/insmod kaodv.o ifname=%s &>/dev/null", ifname);
     system(buf);
 
+#ifdef MAODV
+	if(internet_gw_mode) {
+		memset(buf, '0', 64);
+		if(stat("./kinject.o", &st) < 0)
+		sprintf(buf, "/sbin/modprobe kinject &>/dev/null");
+		else
+		sprintf(buf, "/sbin/insmod kinject.o &>/dev/null");
+		system(buf);
+	}
+#endif
+
     /* Check result */
     m = fopen("/proc/modules", "r");
     while (fgets(buf, sizeof(buf), m)) {
@@ -318,6 +304,9 @@
 void remove_modules(void)
 {
     system("/sbin/modprobe -r kaodv &>/dev/null");
+#ifdef MAODV
+    system("/sbin/modprobe -r kinject &>/dev/null");
+#endif
     system("/sbin/modprobe -r ip_queue &>/dev/null");
 }
 
@@ -411,6 +400,12 @@
 
 	DEV_IFINDEX(ifreq.ifr_ifindex).ipaddr = ntohl(ina->sin_addr.s_addr);
 
+        #ifdef MAODV
+        /* CHECK */
+        kernel_mrt_vif_add( DEV_IFINDEX(ifreq.ifr_ifindex).ipaddr, 0 );
+
+        #endif
+
 	/* Get netmask of interface... */
 	ina = get_if_info(iface, SIOCGIFNETMASK);
 	if (ina == NULL)
@@ -426,6 +421,11 @@
 
 	DEV_IFINDEX(ifreq.ifr_ifindex).enabled = 1;
 
+#ifdef MAODV
+    /* No injection socket yet openned */
+	DEV_IFINDEX(ifreq.ifr_ifindex).injectfd = -1;
+#endif
+
 	if (this_host.nif >= MAX_NR_INTERFACES)
 	    break;
 
@@ -442,15 +442,19 @@
 	exit(-1);
     }
     if (internet_gw_mode) {
-	if (find_default_gw()) {
 	    log(LOG_NOTICE, 0, __FUNCTION__, "Internet gateway mode enabled!");
 	    this_host.gateway_mode = 1;
-	} else {
-	    this_host.gateway_mode = 0;
-	    sprintf(buf, "/sbin/route add default gw 127.0.0.1 dev lo");
-	    system(buf);
 	}
+
+#ifdef MAODV
+	/* Open up injection for interfaces when in gateway mode */
+	if(this_host.gateway_mode) {
+		for(i = 0; i < this_host.nif; i++) {
+			sprintf(buf, "/proc/net/inject/%s", this_host.devs[i].ifname);
+			this_host.devs[i].injectfd = open(buf, O_WRONLY);
     }
+    }
+#endif
 }
 
 /* This signal handler ensures clean exits */
@@ -594,8 +598,18 @@
     /* Initialize data structures and services... */
     rt_table_init();
     log_init();
-    packet_queue_init();
+#ifdef MAODV
+    if(!internet_gw_mode) {
+	    kernel_mrt_init();
+    }
+#endif
+
     host_init(ifname);
+#ifdef MAODV
+	mrt_table_init();
+	init_packet_cache();
+#endif
+    packet_queue_init();
     packet_input_init();
     aodv_socket_init();
 #ifdef USE_IW_SPY
@@ -665,11 +679,29 @@
 
 static void cleanup(void)
 {
+	int i;
+
     DEBUG(LOG_DEBUG, 0, "CLEANING UP!");
-    if (internet_gw_mode && !this_host.gateway_mode)
-	system("/sbin/route del default");
+
+#ifdef MAODV
+	/* Close the injection sockets prior to unloading kinject.o */
+	for(i = 0; i < this_host.nif; i++) {
+		if(this_host.devs[i].injectfd != -1) {
+			close(this_host.devs[i].injectfd);
+			this_host.devs[i].injectfd = -1;
+		}
+	}
+#endif
+
     remove_modules();
     rt_table_destroy();
+#ifdef MAODV
+    mrt_table_destroy();
+
+    /* CHECK: What interface? should we cycle through and fins a nice interface? */
+    kernel_mrt_vif_del( DEV_IFINDEX(0).ipaddr, 0 );
+    kernel_mrt_clean_up();
+#endif
     packet_input_cleanup();
     packet_queue_destroy();
     aodv_socket_cleanup();
diff -urNb aodv-uu-0.7.2/maodv_ext.h maodv-umd-0.7.2/maodv_ext.h
--- aodv-uu-0.7.2/maodv_ext.h	Wed Dec 31 19:00:00 1969
+++ maodv-umd-0.7.2/maodv_ext.h	Wed Jun 25 17:46:09 2003
@@ -0,0 +1,98 @@
+/*****************************************************************************
+ *
+ * Copyright (C) 2003 CSHCN, University of Maryland.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Authors: Dionysus Blazakis <dblaze@umd.edu>
+ *          Jonathan Polley <jpolley@umd.edu>
+ *          Dan Rusk <drusk@umd.edu>
+ *          Manish Karir <karir@umd.edu>
+ *
+ *****************************************************************************/
+
+#ifndef MAODV_EXT_H
+#define MAODV_EXT_H
+
+#ifndef NS_NO_GLOBALS
+#include <endian.h>
+
+#include "defs.h"
+
+typedef struct _grp_leader_ext_t {
+    u_int8_t type;
+    u_int8_t length;
+    u_int32_t grp_leader_addr;
+    u_int32_t prev_hop_addr;
+} grp_leader_ext;
+
+typedef struct _grp_rebuild_ext_t {
+    u_int8_t type;
+    u_int8_t length;
+    u_int16_t grp_hcnt;
+} grp_rebuild_ext;
+
+typedef struct _grp_info_ext_t {
+    u_int8_t type;
+    u_int8_t length;
+    u_int32_t grp_hcnt;
+    u_int32_t grp_leader_addr;
+} grp_info_ext;
+
+/* See note below. */
+typedef struct _grp_merge_ext_t {
+    u_int8_t type;
+    u_int8_t length;
+    u_int16_t res;
+    u_int32_t grp_addr;
+    u_int32_t grp_seqno;
+} grp_merge_ext;
+
+#define GRP_LEADER_EXT        (grp_leader_ext)
+#define GRP_LEADER_EXT_SIZE   ( sizeof(GRP_LEADER_EXT) )
+#define GLE_TYPE              ( 3 )
+                              /* 2 = size of header */
+#define GLE_LENGTH            (GRP_LEADER_EXT_SIZE - 2)  
+
+#define GRP_REBUILD_EXT       grp_rebuild_ext
+#define GRP_REBUILD_EXT_SIZE  ( sizeof(GRP_REBUILD_EXT) )
+#define GRE_TYPE              ( 4 )
+                              /* 2 = size of header */
+#define GRE_LENGTH            (GRP_REBUILD_EXT_SIZE - 2)
+
+#define GRP_INFO_EXT          (grp_info_ext)
+#define GRP_INFO_EXT_SIZE     ( sizeof(GRP_INFO_EXT) )
+#define GIE_TYPE              ( 5 )
+                              /* 2 = size of header */
+#define GIE_LENGTH            (GRP_INFO_EXT_SIZE - 2)
+
+/* NOTE: This is a non-standard extension.  The draft is
+   unclear about the tree merge process.  We have created
+   a new extension for our tree merge.  The type number
+   was chosen in an attempt to avoid collisions with any
+   future extensions. */
+#define GRP_MERGE_EXT         grp_merge_ext
+#define GRP_MERGE_EXT_SIZE    ( sizeof(GRP_MERGE_EXT) )
+#define GME_TYPE              ( 9 )
+                              /* 2 = size of header */
+#define GME_LENGTH            (GRP_MERGE_EXT_SIZE - 2)
+
+#endif				/* NS_NO_GLOBALS */
+
+#ifndef NS_NO_DECLARATIONS
+
+#endif				/* NS_NO_DECLARATIONS */
+
+#endif				/* MAODV_MACT_H */
diff -urNb aodv-uu-0.7.2/maodv_grph.c maodv-umd-0.7.2/maodv_grph.c
--- aodv-uu-0.7.2/maodv_grph.c	Wed Dec 31 19:00:00 1969
+++ maodv-umd-0.7.2/maodv_grph.c	Mon Jun 30 13:53:47 2003
@@ -0,0 +1,226 @@
+#ifdef MAODV
+
+/*****************************************************************************
+ *
+ * Copyright (C) 2003 CSHCN, University of Maryland.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Authors: Dionysus Blazakis <dblaze@umd.edu>
+ *          Jonathan Polley <jpolley@umd.edu>
+ *          Dan Rusk <drusk@umd.edu>
+ *          Manish Karir <karir@umd.edu>
+ *          Jonathan McGee <mcgee@umd.edu>
+ *
+ *****************************************************************************/
+
+#ifdef NS_PORT
+#include "aodv-uu.h"
+#else
+#include <netinet/in.h>
+#include "maodv_grph.h"
+#include "aodv_socket.h"
+#include "params.h"
+#include "seek_list.h"
+#include "defs.h"
+#include "debug.h"
+#include "multicast_routing_table.h"
+#include "aodv_rreq.h"
+#endif
+
+GRPH *grph_create(u_int8_t flags, u_int8_t hcnt, u_int32_t grp_leader_addr, u_int32_t grp_addr, u_int32_t grp_seqno) 
+{
+    GRPH *grph;
+
+    grph=(GRPH *)aodv_socket_new_msg();
+
+    grph->type=MAODV_GRPH;
+    grph->res1=0;
+    grph->res2=0;
+    grph->hcnt=hcnt;
+    grph->grp_leader_addr=htonl(grp_leader_addr);
+    grph->grp_addr=htonl(grp_addr);
+    grph->grp_seqno=htonl(grp_seqno);
+
+    if(flags & GRPH_UPDATE)
+        grph->u=1;
+    if(flags & GRPH_OFFMTREE)
+        grph->o=1;
+
+    DEBUG(LOG_DEBUG, 0, "Assembled GRPH %s", ip_to_str(grp_addr));
+    if(grph->u){
+        DEBUG(LOG_DEBUG, 0, "GRPH->u set");
+    }
+
+    return grph;
+}
+
+void grph_send(u_int8_t flags, u_int8_t hcnt, u_int32_t grp_addr, u_int32_t grp_seqno) 
+{
+    GRPH *grph;
+    int i;
+    /* ttl is one, packets get rebroadcast at each step */
+    int ttl = NET_DIAMETER;
+
+    for(i=0; i<MAX_NR_INTERFACES; i++) {
+        if (!DEV_NR(i).enabled)
+            continue;
+
+        /* CHECK:  Will things break with different ip's per if for leader? */
+
+        grph=grph_create(flags, hcnt, DEV_NR(i).ipaddr, grp_addr, grp_seqno);
+        aodv_socket_send((AODV_msg *)grph, AODV_BROADCAST, GRPH_SIZE, ttl, &DEV_NR(i));
+    }
+}
+
+void grph_forward(GRPH *grph, int ttl)
+{
+    int i;
+    DEBUG(LOG_DEBUG, 0, "forwarding GRPH about %s", ip_to_str(ntohl(grph->grp_addr)));
+
+    grph = (GRPH *) aodv_socket_queue_msg((AODV_msg *) grph, GRPH_SIZE);
+    grph->hcnt++;
+    for(i=0; i<MAX_NR_INTERFACES; i++) {
+        if (!DEV_NR(i).enabled)
+            continue;
+        aodv_socket_send((AODV_msg *)grph, AODV_BROADCAST, GRPH_SIZE, ttl, &DEV_NR(i));
+    }
+}
+
+/* special forwarding: unicast to your upstream */
+void grph_forward_ucast(mrt_table_t *mrt, GRPH *grph, int ttl)
+{
+    mrt_nexthop_t *upstream;
+    rt_table_t *rt;
+    
+    DEBUG(LOG_DEBUG, 0, "forwarding GRPH about %s upstream",
+            ip_to_str(ntohl(grph->grp_addr)));
+
+    upstream=mrt_table_get_activated_upstream(mrt);
+    if(upstream != NULL){
+        rt=rt_table_find(upstream->addr);
+        grph->hcnt++;
+        grph = (GRPH *) aodv_socket_queue_msg((AODV_msg *) grph, GRPH_SIZE);
+        aodv_socket_send((AODV_msg *)grph, upstream->addr, GRPH_SIZE, ttl, &DEV_IFINDEX(rt->ifindex));
+    }
+}
+
+void grph_process(GRPH *grph, u_int32_t src_addr, int ttl)
+{
+    mrt_table_t *mrt;
+    u_int32_t grp_addr;
+    u_int32_t grp_leader_addr;
+    u_int32_t grp_seqno;
+    int do_forward=0, do_forward_ucast=0;
+    u_int8_t new_hcnt;
+
+    grp_addr=ntohl(grph->grp_addr);
+    grp_leader_addr=ntohl(grph->grp_leader_addr);
+    grp_seqno=ntohl(grph->grp_seqno);
+    new_hcnt=grph->hcnt+1;
+    
+    mrt=mrt_table_find(grp_addr);
+    if(mrt==NULL){
+        mrt=mrt_table_insert(grp_addr, grp_leader_addr, grp_seqno, 0, new_hcnt, 0);
+        do_forward=1;
+    }
+    
+    if(mrt->is_router){
+        mrt_nexthop_t *upstream;
+        upstream=mrt_table_get_activated_upstream(mrt);
+
+        /* group leader doens't need to process grph */
+        /* nor do I care about offmtree packets if I'm on the tree */
+        if(mrt->am_leader){
+            if(mrt->grp_leader_addr != grp_leader_addr){
+                /* initiate tree merge */
+                /* Check IP's */
+                if ( ( mrt->grp_leader_addr < grp_leader_addr ) &&
+                   ( !mrt->in_repair ) ){
+                    /* my IP is less than his ;( */
+                    /* initiate route discovery with all the flags */
+                    DEBUG(LOG_DEBUG, 0, "Initiating tree merge for %s.", ip_to_str(grp_addr));
+
+                    mrt->in_repair = 1;
+                    rreq_route_discovery( grp_leader_addr, 
+                        RREQ_JOIN | RREQ_REPAIR | RREQ_DEST_ONLY,
+                        NULL, mrt->grp_addr );
+                }
+            }
+        }else if(!grph->o){
+            if(upstream != NULL && src_addr==upstream->addr){
+                mrt->leader_hcnt=new_hcnt;
+                mrt->grp_seqno=grp_seqno;
+
+                if(grph->u || mrt->grp_leader_addr!=grp_leader_addr){
+                    mrt_table_set_leader(mrt, grp_leader_addr, new_hcnt);
+                }
+                do_forward=1;
+            }
+        }
+        
+        if(!mrt->am_leader && grp_leader_addr != mrt->grp_leader_addr){
+            /* if you get a grph for a different leader.... */
+            /* unicast it to your upstream */
+            do_forward_ucast=1;
+        }
+    }else{
+        /* if not on the tree, you can be less discriminating about 
+           your information */
+        grph->o=1;
+        /* potential method for forwarding grph */
+        if(grp_seqno>mrt->grp_seqno || 
+          (grp_seqno==mrt->grp_seqno && new_hcnt<mrt->leader_hcnt)){
+            do_forward=1;
+        }
+        if(mrt->grp_leader_addr!=grp_leader_addr ||
+          (mrt->grp_leader_addr==grp_leader_addr && new_hcnt<mrt->leader_hcnt)){
+            mrt_table_set_leader(mrt, grp_leader_addr, new_hcnt);
+            do_forward=1;
+        }
+        /* and finally update our sequence number */
+        mrt->grp_seqno=grp_seqno;
+
+    }
+
+    if(do_forward && ttl>1){
+        grph_forward(grph, --ttl);
+    }
+
+    if(do_forward_ucast && ttl>1){
+        grph_forward_ucast(mrt, grph, --ttl);
+    }
+
+    if(this_host.gateway_mode && !mrt->is_router) {
+        /* In Gateway mode, we want a piece of every group */
+        mrt->is_gateway = 1;
+        rreq_route_discovery( grp_addr, RREQ_JOIN, NULL, 0 );
+    }
+}
+
+void grph_send_callback(mrt_table_t *mrt){
+    int flags=0;
+    if(mrt->grph_update_cnt>0){
+        flags=GRPH_UPDATE;
+        mrt->grph_update_cnt--;
+    }
+    if(mrt->am_leader){
+        grph_send(flags, 0, mrt->grp_addr, ++mrt->grp_seqno);
+    
+        timer_set_timeout(&(mrt->grph_timer), GROUP_HELLO_INTERVAL);
+    }
+}
+
+#endif /* MAODV */
diff -urNb aodv-uu-0.7.2/maodv_grph.h maodv-umd-0.7.2/maodv_grph.h
--- aodv-uu-0.7.2/maodv_grph.h	Wed Dec 31 19:00:00 1969
+++ maodv-umd-0.7.2/maodv_grph.h	Wed Jun 25 17:46:09 2003
@@ -0,0 +1,84 @@
+/*****************************************************************************
+ *
+ * Copyright (C) 2003 CSHCN, University of Maryland.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Authors: Dionysus Blazakis <dblaze@umd.edu>
+ *          Jonathan Polley <jpolley@umd.edu>
+ *          Dan Rusk <drusk@umd.edu>
+ *          Manish Karir <karir@umd.edu>
+ *
+ *****************************************************************************/
+
+#ifndef MAODV_GRPH_H
+#define MAODV_GRPH_H
+
+#ifndef NS_NO_GLOBALS
+#include <endian.h>
+
+#include "defs.h"
+#include "multicast_routing_table.h"
+
+/* GRPH Flags: */
+#define GRPH_UPDATE   0x2
+#define GRPH_OFFMTREE 0x1
+
+typedef struct _grph_t {
+    u_int8_t type;
+#  if __BYTE_ORDER == __LITTLE_ENDIAN
+    u_int8_t res1:6;
+    u_int8_t o:1;
+    u_int8_t u:1;
+#  elif __BYTE_ORDER == __BIG_ENDIAN
+    u_int8_t u:1;
+    u_int8_t o:1;
+    u_int8_t res1:6;
+#  else
+#   error "Adjust your <bits/endian.h> defines"
+#  endif
+    u_int8_t res2;
+    u_int8_t hcnt;
+    u_int32_t grp_leader_addr;
+    u_int32_t grp_addr;
+    u_int32_t grp_seqno;
+} grph_t;
+
+#define GRPH grph_t
+#define GRPH_SIZE sizeof(grph_t)
+
+#endif				/* NS_NO_GLOBALS */
+
+#ifndef NS_NO_DECLARATIONS
+GRPH *grph_create(u_int8_t flags,
+        u_int8_t hcnt,
+        u_int32_t grp_leader_addr,
+        u_int32_t grp_addr,
+        u_int32_t grp_seqno);
+
+void grph_send(u_int8_t flags,
+        u_int8_t hcnt,
+        u_int32_t grp_addr,
+        u_int32_t grp_seqno);
+
+void grph_forward(GRPH * GRPH, int ttl);
+
+void grph_process(GRPH * GRPH, u_int32_t src, int ttl);
+
+void grph_send_callback(mrt_table_t *mrt);
+
+#endif				/* NS_NO_DECLARATIONS */
+
+#endif				/* MAODV_GRPH_H */
diff -urNb aodv-uu-0.7.2/maodv_mact.c maodv-umd-0.7.2/maodv_mact.c
--- aodv-uu-0.7.2/maodv_mact.c	Wed Dec 31 19:00:00 1969
+++ maodv-umd-0.7.2/maodv_mact.c	Mon Jun 30 13:53:47 2003
@@ -0,0 +1,302 @@
+#ifdef MAODV
+
+/*****************************************************************************
+ *
+ * Copyright (C) 2003 CSHCN, University of Maryland.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Authors: Dionysus Blazakis <dblaze@umd.edu>
+ *          Jonathan Polley <jpolley@umd.edu>
+ *          Dan Rusk <drusk@umd.edu>
+ *          Manish Karir <karir@umd.edu>
+ *          Jonathan McGee <mcgee@umd.edu>
+ *
+ *****************************************************************************/
+
+#ifdef NS_PORT
+#include "aodv-uu.h"
+#else
+#include <netinet/in.h>
+#include "maodv_mact.h"
+#include "maodv_grph.h"
+#include "aodv_socket.h"
+#include "params.h"
+#include "seek_list.h"
+#include "defs.h"
+#include "debug.h"
+#include "multicast_routing_table.h"
+#include "packet_queue.h"
+#endif
+
+MACT *mact_create(u_int8_t flags, u_int8_t hcnt, u_int32_t src_addr, 
+    u_int32_t grp_addr)
+{
+    MACT *mact;
+
+    mact=(MACT *)aodv_socket_new_msg();
+
+    mact->type=MAODV_MACT;
+    mact->res1=0;
+    mact->res2=0;
+    mact->hcnt=hcnt;
+    mact->grp_addr=htonl(grp_addr);
+    mact->src_addr=htonl(src_addr);
+    mact->src_seqno=htonl(++this_host.seqno);
+
+    /* handle flags */
+    if(flags & MACT_JOIN)
+        mact->j=1;
+    if(flags & MACT_PRUNE)
+        mact->p=1;
+    if(flags & MACT_GRPL)
+        mact->g=1;
+    if(flags & MACT_UPDATE)
+        mact->u=1;
+    if(flags & MACT_REBOOT)
+        mact->r=1;
+
+    DEBUG(LOG_DEBUG, 0, "Assembled MACT %s", ip_to_str(grp_addr));
+
+    return mact;
+}
+
+void mact_send(u_int8_t flags, u_int8_t hcnt, u_int32_t grp_addr, u_int32_t dst_addr, int ttl)
+{
+    MACT *mact;
+    rt_table_t *route;
+    int i;
+
+    route=rt_table_find(dst_addr);
+    i=route->ifindex;
+    mact=mact_create(flags, hcnt, DEV_IFINDEX(i).ipaddr, grp_addr);
+
+    aodv_socket_send((AODV_msg *)mact, dst_addr, MACT_SIZE, ttl, &DEV_IFINDEX(i));
+}
+
+void mact_mcast(u_int8_t flags, u_int8_t hcnt, u_int32_t grp_addr, int ttl)
+{
+    MACT *mact;
+    mrt_table_t *group_rec;
+    mrt_nexthop_t *nexthop;
+    rt_table_t *route;
+    /* prevent sending packet twice on an iface */
+    static char ifmask[MAX_NR_INTERFACES];
+    int i;
+
+    bzero(ifmask, sizeof(ifmask)*sizeof(char));
+
+    group_rec=mrt_table_find(grp_addr);
+    nexthop=group_rec->nexthops;
+
+    /* an attempt to send multicast packets right.
+     * destination is group address
+     * only send one per interface you are currently multicasting to group on
+     */
+    while(nexthop!=NULL) {
+        route=rt_table_find(nexthop->addr);
+        i=route->ifindex;
+        if (!DEV_IFINDEX(i).enabled)
+            continue;
+        if (!ifmask[i]) {
+            mact=mact_create(flags, hcnt, DEV_IFINDEX(i).ipaddr, grp_addr);
+            aodv_socket_send((AODV_msg *)mact, grp_addr, MACT_SIZE, ttl, &DEV_IFINDEX(i));
+            ifmask[i]=1;
+        }
+        nexthop=nexthop->next;
+    }
+}
+
+void mact_process(MACT *mact)
+{
+    u_int32_t src_addr, grp_addr, src_seqno;
+    u_int8_t hcnt;
+    mrt_table_t *group_rec;
+
+    src_addr=ntohl(mact->src_addr);
+    grp_addr=ntohl(mact->grp_addr);
+    src_seqno=ntohl(mact->src_seqno);
+    hcnt=mact->hcnt;
+
+    group_rec=mrt_table_find(grp_addr);
+
+    if(group_rec == NULL) {
+        /* shouldn't happen */
+        return;
+    }
+
+    if(mact->j) {
+        /* JOIN */
+        /* sender wants to join specified group with us as next hop.
+         * if we are already in group, then fine, else need to
+         * pseudo-join ourselves.
+         */
+        mrt_nexthop_t *nh;
+        
+        nh=mrt_nexthop_find(group_rec, src_addr);
+        if(nh==NULL){
+            nh=mrt_nexthop_add(group_rec, src_addr, MRT_DOWNSTREAM, src_seqno);
+        }
+        if(nh->activated){
+            mrt_nexthop_deactivate(group_rec, nh->addr);
+        }
+        if ( nh->direction==MRT_UPSTREAM) {
+            nh->direction=MRT_DOWNSTREAM;
+        }
+        mrt_nexthop_activate(group_rec, src_addr);
+        DEBUG(LOG_DEBUG, 0, "activated downstream %s", ip_to_str(src_addr));
+
+        /* check if we are not leader and yet have no upstream*/
+        if(!group_rec->am_leader && group_rec->activated_upstream_cnt==0) {
+            /* not leader and no upstream, so activate one */
+            mact_activate_best_upstream(group_rec);
+        }
+
+
+    }else if(mact->p) {
+        /* PRUNE */
+        mrt_nexthop_t *nexthop;
+        
+        DEBUG(LOG_DEBUG, 0, "Entered mact->p handler");
+       
+        nexthop=mrt_table_get_activated_upstream(group_rec);
+        if(nexthop!=NULL && nexthop->addr==src_addr){
+            DEBUG(LOG_DEBUG, 0, "\tUpstream sent prune");
+            /* deactivate said upstream in our records */
+            mrt_nexthop_deactivate(group_rec, nexthop->addr);
+            /* upstream sent us prune */
+            /* if member, become leader, else leave and make a downstream */
+            if(group_rec->is_member || (group_rec->is_gateway
+                        && group_rec->activated_downstream_cnt > 0)){
+                mrt_table_become_leader(group_rec);
+            }else{
+                mact_make_downstream_leader(group_rec);
+            }
+        }
+
+        /* if no other downstreams and not listening ourselves, prune self */
+        else if(!group_rec->is_member
+                && (!group_rec->is_gateway || group_rec->activated_upstream_cnt == 0)
+                && (group_rec->activated_downstream_cnt == 1)) {
+            mrt_nexthop_t *upstream;
+            /* Gateway code can create non-member leaders */
+            group_rec->is_gateway = 0;
+            group_rec->am_leader = 0;
+            upstream=mrt_table_get_activated_upstream(group_rec);
+            DEBUG(LOG_DEBUG, 0, "\tDownstream sent prune, prune self");
+            if(upstream != NULL){
+                mact_send(MACT_PRUNE, 1, grp_addr, upstream->addr,1);
+                mrt_nexthop_deactivate(group_rec, upstream->addr);
+            }
+            mrt_table_stop_routing(group_rec);
+        }else{
+            DEBUG(LOG_DEBUG, 0, "\tDownstream sent prune, stay on tree");
+        }
+
+        /* remove them */
+        mrt_nexthop_deactivate(group_rec, src_addr);
+    } else if(mact->g) {
+        /* GR/OUP LEADER
+         * 
+         * my upstream may send it to me.
+         * either I become leader or I promote a child
+         */
+
+        /* node who sent it has me marked as its upstream now */
+        mrt_nexthop_t *node;
+        node=mrt_table_get_activated_upstream(group_rec);
+        if(node!=NULL){
+            node->direction=MRT_DOWNSTREAM;
+            group_rec->activated_upstream_cnt--;
+            group_rec->activated_downstream_cnt++;
+        }
+        
+        if(group_rec->is_member) {
+            /* declare myself leader */
+            /* TODO: might need to set U flag on first one */
+
+            mrt_table_become_leader(group_rec);
+        } else {
+            /* send a notice to a downstream making it leader */
+            mact_make_downstream_leader(group_rec);
+        }
+    } else if(mact->u) {
+        /* UPDATE */
+    } else if(mact->r) {
+        /* REBOOT */
+    }
+}
+
+mrt_nexthop_t *mact_activate_best_upstream(mrt_table_t *mrt){
+    mrt_nexthop_t *besthop=NULL;
+
+    besthop=mrt_table_get_best_upstream(mrt);
+
+    /* and activate it */
+    if(besthop!=NULL){
+        mrt_table_start_routing(mrt);
+
+        mrt_nexthop_activate(mrt, besthop->addr);
+        mact_send(MACT_JOIN, 1, mrt->grp_addr, besthop->addr, 1);
+        DEBUG(LOG_DEBUG, 0, "activated upstream %s", ip_to_str(besthop->addr));
+
+        if ( seek_list_remove(seek_list_find(mrt->grp_addr) ) ) {
+            mcast_packet_queue_send( mrt->grp_addr );
+        }
+    }
+
+    return besthop;
+}
+
+void mact_make_downstream_leader(mrt_table_t *group_rec){
+    mrt_nexthop_t *downstream;
+    DEBUG(LOG_DEBUG, 0, "Entered mact_make_downstream_leader");
+    
+    if(group_rec->activated_downstream_cnt==0){
+        DEBUG(LOG_DEBUG, 0, "No downstreams to make leader!  Clearing flags");
+        mrt_table_stop_routing(group_rec);
+        group_rec->is_gateway = 0;
+        return;
+    }
+    
+    downstream=group_rec->nexthops;
+    while(downstream->direction!=MRT_DOWNSTREAM || !downstream->activated){
+        downstream=downstream->next;
+    }
+    
+    if(group_rec->activated_downstream_cnt==1){
+        /* one child, make him leader */
+        DEBUG(LOG_DEBUG, 0, "\tEntered one child version");
+        mact_send(MACT_PRUNE, 0, group_rec->grp_addr, downstream->addr,1);
+        mrt_nexthop_deactivate(group_rec, downstream->addr);
+        mrt_table_stop_routing(group_rec);
+
+        /* remove any pending RREQs (or other packets) for this group */
+        seek_list_remove(seek_list_find(group_rec->grp_addr));
+        packet_queue_drop(group_rec->grp_addr);
+
+        /* flush all nexthops */
+        mrt_nexthop_remove_all(group_rec);
+    }else{
+        /* send a 'G' mact to an arbitrary child, then make it upstream */
+        DEBUG(LOG_DEBUG, 0, "\tEntered many child version (where you stay as router)");
+        mact_send(MACT_GRPL, 0, group_rec->grp_addr, downstream->addr,1);
+        downstream->direction=MRT_UPSTREAM;
+        group_rec->activated_downstream_cnt--;
+        group_rec->activated_upstream_cnt++;
+    }
+}
+
+#endif /* MAODV */
diff -urNb aodv-uu-0.7.2/maodv_mact.h maodv-umd-0.7.2/maodv_mact.h
--- aodv-uu-0.7.2/maodv_mact.h	Wed Dec 31 19:00:00 1969
+++ maodv-umd-0.7.2/maodv_mact.h	Wed Jun 25 17:46:10 2003
@@ -0,0 +1,98 @@
+/*****************************************************************************
+ *
+ * Copyright (C) 2003 CSHCN, University of Maryland.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Authors: Dionysus Blazakis <dblaze@umd.edu>
+ *          Jonathan Polley <jpolley@umd.edu>
+ *          Dan Rusk <drusk@umd.edu>
+ *          Manish Karir <karir@umd.edu>
+ *
+ *****************************************************************************/
+
+#ifndef MAODV_MACT_H
+#define MAODV_MACT_H
+
+#ifndef NS_NO_GLOBALS
+#include <endian.h>
+
+#include "defs.h"
+#include "multicast_routing_table.h"
+
+/* MACT Flags: */
+#define MACT_JOIN   0x10
+#define MACT_PRUNE  0x08
+#define MACT_GRPL   0x04
+#define MACT_UPDATE 0x02
+#define MACT_REBOOT 0x01
+
+typedef struct _mact_t {
+    u_int8_t type;
+#  if __BYTE_ORDER == __LITTLE_ENDIAN
+    u_int8_t res1:3;
+    u_int8_t r:1;
+    u_int8_t u:1;
+    u_int8_t g:1;
+    u_int8_t p:1;
+    u_int8_t j:1;
+#  elif __BYTE_ORDER == __BIG_ENDIAN
+    u_int8_t j:1;
+    u_int8_t p:1;
+    u_int8_t g:1;
+    u_int8_t u:1;
+    u_int8_t r:1;
+    u_int8_t res1:3;
+#  else
+#   error "Adjust your <bits/endian.h> defines"
+#  endif
+    u_int8_t res2;
+    u_int8_t hcnt;
+    u_int32_t grp_addr;
+    u_int32_t src_addr;
+    u_int32_t src_seqno;
+} mact_t;
+
+#define MACT mact_t
+#define MACT_SIZE sizeof(MACT)
+
+#endif				/* NS_NO_GLOBALS */
+
+#ifndef NS_NO_DECLARATIONS
+MACT *mact_create(u_int8_t flags,
+        u_int8_t hcnt,
+        u_int32_t src_addr,
+        u_int32_t grp_addr);
+
+void mact_send(u_int8_t flags,
+        u_int8_t hcnt,
+        u_int32_t grp_addr,
+        u_int32_t dst_addr,
+        int ttl);
+
+void mact_mcast(u_int8_t flags,
+        u_int8_t hcnt,
+        u_int32_t grp_addr,
+        int ttl);
+
+void mact_process(MACT *mact);
+
+mrt_nexthop_t *mact_activate_best_upstream(mrt_table_t *mrt);
+void mact_make_downstream_leader(mrt_table_t *mrt);
+
+
+#endif				/* NS_NO_DECLARATIONS */
+
+#endif				/* MAODV_MACT_H */
diff -urNb aodv-uu-0.7.2/maodv_neighbor.c maodv-umd-0.7.2/maodv_neighbor.c
--- aodv-uu-0.7.2/maodv_neighbor.c	Wed Dec 31 19:00:00 1969
+++ maodv-umd-0.7.2/maodv_neighbor.c	Wed Jun 25 17:46:09 2003
@@ -0,0 +1,108 @@
+#ifdef MAODV
+
+/*****************************************************************************
+ *
+ * Copyright (C) 2003 CSHCN, University of Maryland.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Authors: Dionysus Blazakis <dblaze@umd.edu>
+ *          Jonathan Polley <jpolley@umd.edu>
+ *          Dan Rusk <drusk@umd.edu>
+ *          Manish Karir <karir@umd.edu>
+ *          Jonathan McGee <mcgee@umd.edu>
+ *
+ *****************************************************************************/
+
+#include "maodv_neighbor.h"
+#include "routing_table.h"
+#include "multicast_routing_table.h"
+#include "aodv_rreq.h"
+#include "maodv_mact.h"
+#include "debug.h"
+#include "params.h"
+
+void mcast_neighbor_link_break(rt_table_t *rt){
+    mrt_table_t *mrt;
+    mrt_nexthop_t *nexthop;
+    int i;
+    
+    /* determine which, if any, groups the broken node is in */
+    for(i=0; i<MRT_TABLESIZE; i++){
+        mrt=mrt_tbl.tbl[i];
+
+        while(mrt!=NULL){
+            nexthop=mrt_nexthop_find(mrt, rt->dest_addr);
+
+            /* only care about activated routes */
+            if(nexthop!=NULL && nexthop->activated){
+                int nh_dir=nexthop->direction;
+
+                mrt_nexthop_remove(mrt, nexthop->addr);
+                if(nh_dir==MRT_UPSTREAM){
+                    mrt->is_broken = 1;
+
+                    /* we lost our upstream, find a new one */
+                    rreq_route_discovery(mrt->grp_addr, 
+                        RREQ_JOIN|RREQ_GRP_REBUILD, NULL, 0);
+                }else{
+                    /* we lost our downstream, wait to see if he returns */
+                    mrt_nexthop_remove(mrt, nexthop->addr);
+
+                    if(!mrt->is_member && mrt->activated_downstream_cnt==0){
+                        DEBUG(LOG_DEBUG, 0, "setting prune dangle timer");
+
+                        /* set timeout to prune self if downstream doesn't
+                         * reconnect */
+                        mrt->prune_timer.handler = (timeout_func_t) &mcast_prune_dangle;
+                        mrt->prune_timer.data = &mrt;
+
+                        /* 20 seconds of rebuild time. */
+                        timer_set_timeout( &mrt->prune_timer, PRUNE_TIMEOUT );
+                    }
+                }
+            }else if(nexthop!=NULL && !nexthop->activated){
+                mrt_nexthop_remove(mrt, nexthop->addr);
+            }
+            
+            mrt=mrt->next;
+        }
+    }
+}
+
+/* mcast_prune_dangle
+ * if you become a router only with no downstream nodes, (dangling) then
+ * prune self after a timeout */
+void mcast_prune_dangle( mrt_table_t *mrt ) {
+    mrt_nexthop_t * upstream;
+
+    DEBUG(LOG_DEBUG, 0, "in prune dangle timer");
+    if ( mrt->activated_downstream_cnt == 0 && !mrt->is_member 
+            && (!mrt->is_gateway || (mrt->activated_upstream_cnt == 0))) {
+        /* prune me */
+
+        upstream = mrt_table_get_activated_upstream( mrt ); 
+        DEBUG( LOG_DEBUG, 0, "Pruning myself after a reasonable timeout." );
+
+        if(upstream != NULL){
+            mact_send( MACT_PRUNE, 1, mrt->grp_addr, upstream->addr, 1 );
+            mrt_nexthop_deactivate( mrt, upstream->addr );
+        }
+
+        mrt_table_stop_routing(mrt);
+    }
+}
+
+#endif
diff -urNb aodv-uu-0.7.2/maodv_neighbor.h maodv-umd-0.7.2/maodv_neighbor.h
--- aodv-uu-0.7.2/maodv_neighbor.h	Wed Dec 31 19:00:00 1969
+++ maodv-umd-0.7.2/maodv_neighbor.h	Wed Jun 25 17:46:10 2003
@@ -0,0 +1,38 @@
+/*****************************************************************************
+ *
+ * Copyright (C) 2003 CSHCN, University of Maryland.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Authors: Dionysus Blazakis <dblaze@umd.edu>
+ *          Jonathan Polley <jpolley@umd.edu>
+ *          Dan Rusk <drusk@umd.edu>
+ *          Manish Karir <karir@umd.edu>
+ *
+ *****************************************************************************/
+
+#ifndef MAODV_NEIGHBOR_H
+#define MAODV_NEIGHBOR_H
+
+#include "routing_table.h"
+#include "multicast_routing_table.h"
+
+void mcast_neighbor_link_break(rt_table_t *rt);
+/* mcast_prune_dangle
+ * if you become a router only with no downstream nodes, (dangling) then
+ * prune self after a timeout */
+void mcast_prune_dangle( mrt_table_t *mrt );
+
+#endif
diff -urNb aodv-uu-0.7.2/maodv_rrep.c maodv-umd-0.7.2/maodv_rrep.c
--- aodv-uu-0.7.2/maodv_rrep.c	Wed Dec 31 19:00:00 1969
+++ maodv-umd-0.7.2/maodv_rrep.c	Wed Jun 25 17:46:10 2003
@@ -0,0 +1,191 @@
+#ifdef MAODV
+
+/*****************************************************************************
+ *
+ * Copyright (C) 2003 CSHCN, University of Maryland.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Authors: Dionysus Blazakis <dblaze@umd.edu>
+ *          Jonathan Polley <jpolley@umd.edu>
+ *          Dan Rusk <drusk@umd.edu>
+ *          Manish Karir <karir@umd.edu>
+ *
+ *****************************************************************************/
+
+#include "defs.h"
+#include "debug.h"
+#include "maodv_rrep.h"
+#include "routing_table.h"
+#include "multicast_routing_table.h"
+#include "aodv_socket.h"
+#include "aodv_rreq.h"
+#include "aodv_rrep.h"
+#include "packet_queue.h"
+
+/*
+ *  maodv_rrep_process( lots of stuff )
+ *  Processes an rrep that has already been sanity checked and is
+ *  responding to a multicast group.
+ */
+void maodv_rrep_process( RREP *rrep, int rreplen, u_int32_t ip_src,  
+    u_int32_t ip_dst, int ip_ttl, unsigned int ifindex, int size )
+{
+    mrt_nexthop_t * upstream;
+    mrt_table_t * mrt;
+    rt_table_t * rev_rt;
+    u_int32_t rrep_orig, rrep_dest, rrep_seqno, rrep_lifetime;
+    mrt_orig_t *orig;
+    
+    DEBUG( LOG_DEBUG, 0, "Inside RREP process." );
+
+    rrep_dest = ntohl(rrep->dest_addr);
+    rrep_seqno = ntohl(rrep->dest_seqno);
+    rrep_orig = ntohl(rrep->orig_addr);
+    rrep_lifetime = ntohl(rrep->lifetime);
+
+    rev_rt = rt_table_find( rrep_orig );
+    mrt = mrt_table_find( rrep_dest );
+
+    if ( !mrt ) {
+        log(LOG_WARNING, 0, __FUNCTION__,
+            "No multicast route to group %s found in RREP.",
+            ip_to_str( rrep_dest ) );
+        return;
+    }
+
+    upstream = mrt_nexthop_find(mrt, ip_src);
+    if(upstream == NULL){
+        DEBUG( LOG_DEBUG, 0, "Created nexthop." );
+        upstream = mrt_nexthop_add( mrt, ip_src, MRT_UPSTREAM, rrep_seqno );
+    } else {
+        /* update seqno */
+        DEBUG( LOG_DEBUG, 0, "Had nexthop, updated seqno." );
+        upstream->grp_seqno = rrep_seqno;
+    }
+    
+    /* add the originator to the originator list if not there already */
+    orig=mrt_origlist_find(mrt, rrep_orig);
+    if(orig==NULL){
+        DEBUG(LOG_DEBUG, 0, "originator not in list, adding");
+        orig=mrt_origlist_add(mrt, rrep_orig);
+    }
+ 
+    DEBUG(LOG_DEBUG, 0, "originator seqno: %d hcnt: %d", orig->grp_seqno, 
+        orig->grp_hcnt);
+
+    /* rrep is propagated if the prior rreq had a lower
+       sequence number or the sequence numbers are equal and the
+       incoming rrep has a smaller hopcount */ 
+    if ( ( ( orig->grp_seqno < rrep_seqno ) ||
+           ( ( orig->grp_seqno == rrep_seqno ) &&
+             ( orig->grp_hcnt > rrep->hcnt ) ) ) ){
+
+        DEBUG( LOG_DEBUG, 0, "Forwardable/acceptable rrep." );
+
+        mrt->grp_seqno = rrep_seqno;
+        orig->grp_seqno=rrep_seqno;
+        orig->grp_hcnt = rrep->hcnt;
+
+        if ( !upstream->activated ) {
+            upstream->direction = MRT_UPSTREAM;
+            upstream->grp_hcnt = rrep->hcnt;
+        }
+        
+        if ( rrep_orig != DEV_IFINDEX(ifindex).ipaddr )
+            maodv_rrep_forward( rrep, rev_rt, mrt, --ip_ttl, size );
+    } else {
+        DEBUG( LOG_DEBUG, 0,"mrt->grp_seqno: %d\trrep_seqno: %d", 
+            mrt->grp_seqno, rrep_seqno );
+    }
+}
+
+void maodv_rrep_forward( RREP * rrep, rt_table_t * rev_rt,
+    mrt_table_t * fwd_rt, int ttl, int size )
+{
+    mrt_nexthop_t * upstream;
+
+    if (!fwd_rt || !rev_rt) {
+        DEBUG(LOG_WARNING, 0, "Could not forward RERR because of NULL route!");
+        return;
+    }
+
+    if (!rrep) {
+        DEBUG(LOG_WARNING, 0, "No RREP to forward!");
+        return;
+    }
+
+    DEBUG(LOG_DEBUG, 0, "Forwarding RREP to %s", ip_to_str(rev_rt->next_hop));
+
+    rrep = (RREP *) aodv_socket_queue_msg((AODV_msg *) rrep, size);
+    upstream = mrt_table_get_best_upstream( fwd_rt );
+    
+    /* Update the hopcount */
+    if(!fwd_rt->is_router){
+        rrep->hcnt++;
+    }
+
+    aodv_socket_send((AODV_msg *) rrep, rev_rt->next_hop, size, ttl,
+                     &DEV_IFINDEX(rev_rt->ifindex));
+
+    /* TODO: timing code... */
+/*    rt_table_update_timeout(rev_rt, ACTIVE_ROUTE_TIMEOUT); */
+}
+
+void maodv_rrep_send( rt_table_t * rev_rt, mrt_table_t * fwd_rt )
+{
+    RREP *rrep;
+    u_int8_t rrep_flags = 0;
+    u_int32_t dest, lifetime;
+    int hcnt;
+
+    /* CHECK: we do not use this... */
+    lifetime = 0x0ffffffff;
+
+    if (!rev_rt) {
+        DEBUG(LOG_WARNING, 0, "Can't send RREP, rev_rt = NULL!");
+        return;
+    }
+
+    if (!fwd_rt) {
+        DEBUG(LOG_WARNING, 0, "Can't send RREP, fwd_rt = NULL!");
+        return;
+    }
+
+    DEBUG(LOG_DEBUG, 0, "[maodv] sending rrep.");
+
+    dest = fwd_rt->grp_addr;
+
+    hcnt = 0;
+
+    /* TODO: timeout code... */
+    /*
+    gettimeofday(&now, NULL);
+    lifetime = timeval_diff(&fwd_rt->rt_timer.timeout, &now);
+    */
+
+    DEBUG(LOG_DEBUG, 0, "[maodv] Sending RREP to %s about %s->%s",
+          ip_to_str(rev_rt->next_hop), ip_to_str(rev_rt->dest_addr),
+          ip_to_str(dest));
+
+    rrep = rrep_create(rrep_flags, 0, hcnt, dest, fwd_rt->grp_seqno, 
+        rev_rt->dest_addr, lifetime, 0 );
+        
+    aodv_socket_send((AODV_msg *) rrep, rev_rt->next_hop, RREP_SIZE, MAXTTL,
+                     &DEV_IFINDEX(rev_rt->ifindex));
+
+}
+
+#endif /* MAODV */
diff -urNb aodv-uu-0.7.2/maodv_rrep.h maodv-umd-0.7.2/maodv_rrep.h
--- aodv-uu-0.7.2/maodv_rrep.h	Wed Dec 31 19:00:00 1969
+++ maodv-umd-0.7.2/maodv_rrep.h	Wed Jun 25 17:46:10 2003
@@ -0,0 +1,41 @@
+/*****************************************************************************
+ *
+ * Copyright (C) 2003 CSHCN, University of Maryland.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Authors: Dionysus Blazakis <dblaze@umd.edu>
+ *          Jonathan Polley <jpolley@umd.edu>
+ *          Dan Rusk <drusk@umd.edu>
+ *          Manish Karir <karir@umd.edu>
+ *
+ *****************************************************************************/
+
+#ifndef MAODV_RREP_H
+#define MAODV_RREP_H
+
+#include "routing_table.h"
+#include "multicast_routing_table.h"
+#include "aodv_rrep.h"
+
+void maodv_rrep_process( RREP *rrep, int rreplen, u_int32_t ip_src,  
+    u_int32_t ip_dst, int ip_ttl, unsigned int ifindex, int size );
+
+void maodv_rrep_forward( RREP * rrep, rt_table_t * rev_rt,
+    mrt_table_t * fwd_rt, int ttl, int size );
+
+void maodv_rrep_send( rt_table_t * rev_rt, mrt_table_t * fwd_rt );
+
+#endif
diff -urNb aodv-uu-0.7.2/maodv_rreq.c maodv-umd-0.7.2/maodv_rreq.c
--- aodv-uu-0.7.2/maodv_rreq.c	Wed Dec 31 19:00:00 1969
+++ maodv-umd-0.7.2/maodv_rreq.c	Wed Jun 25 17:46:10 2003
@@ -0,0 +1,175 @@
+#ifdef MAODV
+
+/*****************************************************************************
+ *
+ * Copyright (C) 2003 CSHCN, University of Maryland.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Authors: Dionysus Blazakis <dblaze@umd.edu>
+ *          Jonathan Polley <jpolley@umd.edu>
+ *          Dan Rusk <drusk@umd.edu>
+ *          Manish Karir <karir@umd.edu>
+ *
+ *****************************************************************************/
+
+#include "defs.h"
+#include "debug.h"
+#include "maodv_rreq.h"
+#include "maodv_rrep.h"
+#include "multicast_routing_table.h"
+#include "aodv_socket.h"
+#include "aodv_rreq.h"
+#include "aodv_rrep.h"
+#include "maodv_ext.h"
+
+/*
+ *  maodv_rreq_process( lots of stuff )
+ *  Processes an rreq that has already been sanity checked and is
+ *  headed for a multicast group.
+ */
+void maodv_rreq_process( RREQ *rreq, int rreqlen, u_int32_t ip_src,  
+    u_int32_t ip_dst, int ip_ttl, unsigned int ifindex, 
+    GRP_REBUILD_EXT *grb_ext, int size )
+{
+    mrt_table_t * mrt;
+    rt_table_t * rev_rt;
+    u_int32_t rreq_orig, rreq_dest, rreq_orig_seqno, rreq_dest_seqno;
+    u_int32_t rreq_id, rreq_new_hcnt;
+    mrt_nexthop_t * nh;
+    mrt_orig_t *orig;
+    
+    DEBUG( LOG_DEBUG, 0, "Inside RREP process." );
+
+    rreq_id = ntohl(rreq->rreq_id);
+    rreq_dest = ntohl(rreq->dest_addr);
+    rreq_dest_seqno = ntohl(rreq->dest_seqno);
+    rreq_orig = ntohl(rreq->orig_addr);
+    rreq_orig_seqno = ntohl(rreq->orig_seqno);
+    rreq_new_hcnt = rreq->hcnt + 1;
+
+    mrt = mrt_table_find( rreq_dest );
+    if ( mrt==NULL ) {
+        /* no route found */
+        DEBUG(LOG_DEBUG, 0, "MRREQ: No mrt found." );
+        mrt = mrt_table_insert( rreq_dest, 0, rreq_dest_seqno, 
+            ifindex, 255, 0 );
+    }
+
+    /* add nexthop downstream */
+    nh = mrt_nexthop_find( mrt, rreq_orig );
+    if ( nh == NULL ) {
+        mrt_nexthop_add( mrt, ip_src, MRT_DOWNSTREAM, rreq_dest_seqno );
+    }
+
+    /* add the originator to the originator list if not there already */
+    orig=mrt_origlist_find(mrt, rreq_orig);
+    if(orig==NULL){
+        DEBUG(LOG_DEBUG, 0, "originator not in list, adding");
+        orig=mrt_origlist_add(mrt, rreq_orig);
+    }
+    DEBUG(LOG_DEBUG, 0, "originator seqno: %d hcnt: %d", orig->grp_seqno, orig->grp_hcnt);
+
+    if ( rreq->j ) {
+        /* a Join request */
+        DEBUG(LOG_DEBUG, 0, "MRREQ: [j] Join." );
+
+        if ( !mrt->is_router) {
+            DEBUG(LOG_DEBUG, 0, "MRREQ: [j] Found a mrt, but not on the tree.");
+        } else if ( mrt->grp_seqno < rreq_dest_seqno ) {
+            DEBUG(LOG_DEBUG, 0, "MRREQ: [j] Found a mrt, but it is old. %d < %d", mrt->grp_seqno, rreq_dest_seqno );
+            mrt->grp_seqno = rreq_dest_seqno;
+        } else {
+            if(grb_ext==NULL || mrt->leader_hcnt<=grb_ext->grp_hcnt){
+                DEBUG(LOG_DEBUG, 0, "MRREQ: [j] Should send RREP!" );
+
+                /* send rrep */
+                rev_rt = rt_table_find( rreq_orig );
+                orig->grp_seqno=mrt->grp_seqno;
+                orig->grp_hcnt=0;
+                maodv_rrep_send( rev_rt, mrt );
+
+                /* done! get out */
+                return; 
+            }else{
+                DEBUG(LOG_DEBUG, 0, "had repair extension, bad hopcount, do nothing");
+            }
+        }
+    } else {
+        /* non-Join request */
+        DEBUG(LOG_DEBUG, 0, "MRREQ: [] non-Join." );
+
+        if ( mrt->grp_seqno < rreq_dest_seqno ) {
+            DEBUG(LOG_DEBUG, 0, "MRREQ: [] Found a mrt, but it is old." );
+            /* update sequence number in our table */
+            mrt->grp_seqno = rreq_dest_seqno;
+        } else if ( mrt->is_router ) {
+            DEBUG(LOG_DEBUG, 0, "MRREQ: [] Should send RREP!" );
+
+            /* send rrep */
+            rev_rt = rt_table_find( rreq_orig );
+            orig->grp_seqno=mrt->grp_seqno;
+            orig->grp_hcnt=0;
+            maodv_rrep_send( rev_rt, mrt );
+
+            /* we're done! */
+            return;
+        }
+    }
+
+    /* if we get this far, no RREP has been sent. */
+
+    /* now, forward RREQ */
+    /* if rreq has unknown seqno and our table has a known one
+       (not zero), then update packet seqno field. or if ours
+       is just bigger.
+       CHECK: this may not be the way to do this */
+    if ( ( mrt->grp_seqno > rreq_dest_seqno ) || 
+         ( rreq->u && mrt->grp_seqno ) ) {
+        rreq->u = 0;
+        rreq->dest_seqno = htonl( mrt->grp_seqno );
+    }
+
+   /* send it back out */
+   maodv_rreq_forward( rreq, --ip_ttl, size );
+}
+
+/*
+ *  maodv_rreq_forward( RREQ * rreq, int ttl, int size )
+ *  Forwards a route request.
+ */
+void maodv_rreq_forward( RREQ * rreq, int ttl, int size )
+{
+    int i;
+    /* FORWARD the RREQ if the TTL allows it. */
+    DEBUG(LOG_DEBUG, 0, "[maodv] forwarding RREQ src=%s, rreq_id=%lu",
+          ip_to_str(ntohl(rreq->orig_addr)), ntohl(rreq->rreq_id));
+            
+    /* Queue the received message in the send buffer */
+    rreq = (RREQ *) aodv_socket_queue_msg((AODV_msg *) rreq, size);
+     
+    rreq->hcnt++;               /* Increase hopcount to account for
+                                 * intermediate route */
+
+    /* Send out on all interfaces */
+    for (i = 0; i < MAX_NR_INTERFACES; i++) {
+        if (!DEV_NR(i).enabled)
+            continue;
+        aodv_socket_send((AODV_msg *) rreq, AODV_BROADCAST, size, ttl,
+                         &DEV_NR(i));
+    }
+}
+
+#endif /* MAODV */
diff -urNb aodv-uu-0.7.2/maodv_rreq.h maodv-umd-0.7.2/maodv_rreq.h
--- aodv-uu-0.7.2/maodv_rreq.h	Wed Dec 31 19:00:00 1969
+++ maodv-umd-0.7.2/maodv_rreq.h	Wed Jun 25 17:46:10 2003
@@ -0,0 +1,39 @@
+/*****************************************************************************
+ *
+ * Copyright (C) 2003 CSHCN, University of Maryland.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Authors: Dionysus Blazakis <dblaze@umd.edu>
+ *          Jonathan Polley <jpolley@umd.edu>
+ *          Dan Rusk <drusk@umd.edu>
+ *          Manish Karir <karir@umd.edu>
+ *
+ *****************************************************************************/
+
+#ifndef MAODV_RREQ_H
+#define MAODV_RREQ_H
+
+#include "defs.h"
+#include "aodv_rreq.h"
+#include "maodv_ext.h"
+
+void maodv_rreq_process( RREQ *rreq, int rreqlen, u_int32_t ip_src,
+    u_int32_t ip_dst, int ip_ttl, unsigned int ifindex, 
+    GRP_REBUILD_EXT *grb_ext, int size );
+
+void maodv_rreq_forward( RREQ * rreq, int ttl, int size );
+
+#endif /* MAODV_RREQ_H */
diff -urNb aodv-uu-0.7.2/multicast_packet_cache.c maodv-umd-0.7.2/multicast_packet_cache.c
--- aodv-uu-0.7.2/multicast_packet_cache.c	Wed Dec 31 19:00:00 1969
+++ maodv-umd-0.7.2/multicast_packet_cache.c	Wed Jun 25 17:46:10 2003
@@ -0,0 +1,80 @@
+#ifdef MAODV
+
+/*****************************************************************************
+ *
+ * Copyright (C) 2003 CSHCN, University of Maryland.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * 
+ * Authors: Matthew Impett <m.impett@flarion.com>
+ *
+ *
+ *****************************************************************************/
+ 
+#include "multicast_packet_cache.h"
+
+void	init_packet_cache(void)
+{
+	int i;
+	int j;
+	for(i=0; i< HASHBUCKETS; i++)
+	{
+		packet_cache[i].packet_cache_write_index = 0;
+		for(j=0; j < MAX_PACKET_CACHE; j++)
+		{
+			packet_cache[i].ip_src[j] = 0;
+			packet_cache[i].ip_id[j] = 0;
+			packet_cache[i].ip_hook[j] = 0;
+		}
+	}
+}
+
+/* This function returns 1 if a duplicate packet has not been
+   found and  returns 0 if a duplicate packet has not been found and adds 
+   that packet to the packet cache. */
+int	check_duplicate(u_int32_t src, u_int16_t id, u_int8_t hook)
+{	
+	u_int8_t	hash_value;
+	int i;
+	int j = 0;
+	hash_value = 	packet_hashfunction(src);
+
+	for(i=0; i< MAX_PACKET_CACHE; i++)
+	{
+		if( (packet_cache[hash_value].ip_src[i] == src) &&
+                    (packet_cache[hash_value].ip_id[i] == id) &&
+		    (packet_cache[hash_value].ip_hook[i] == hook) )
+		{
+			/* Found a duplicate packet.... Drop it */
+			return 0;
+		}
+	}
+
+	/* Not found the packet in the cache... Add it to the packet cache */
+
+	j = packet_cache[hash_value].packet_cache_write_index ;	
+	packet_cache[hash_value].ip_src[j] = src;
+	packet_cache[hash_value].ip_id[j] = id;
+	packet_cache[hash_value].ip_hook[j] = hook;
+	packet_cache[hash_value].packet_cache_write_index = (j+1)%(MAX_PACKET_CACHE);
+	return 1;	
+}
+
+u_int8_t	packet_hashfunction(u_int32_t addr)
+{
+	return ((addr >> 24) % HASHBUCKETS);
+}
+
+#endif /* MAODV */
diff -urNb aodv-uu-0.7.2/multicast_packet_cache.h maodv-umd-0.7.2/multicast_packet_cache.h
--- aodv-uu-0.7.2/multicast_packet_cache.h	Wed Dec 31 19:00:00 1969
+++ maodv-umd-0.7.2/multicast_packet_cache.h	Wed Jun 25 17:46:10 2003
@@ -0,0 +1,54 @@
+/*****************************************************************************
+ *
+ * Copyright (C) 2003 CSHCN, University of Maryland.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Authors: Matthew Impett <m.impett@flarion.com>
+ *
+ *
+ *****************************************************************************/
+
+/**********************************************************************
+   The following packet cache has been obtained from Matthew Impett's 
+   TORA implementation code.....  
+ **********************************************************************/
+
+#ifndef MULTICAST_PACKET_CACHE_H
+#define MULTICAST_PACKET_CACHE_H
+
+#include "defs.h"
+
+#define HASHBUCKETS             10   /* number of buckets for entries */
+#define MAX_PACKET_CACHE        10   /* # of packets for each hash bucket */
+
+/* This structure is used to hold a little cache of recently forwarded 
+   packets which we can use to detect duplicate packets. */
+struct pack_cache
+{
+        u_int32_t  	ip_src[MAX_PACKET_CACHE];
+        u_int16_t	ip_id[MAX_PACKET_CACHE];
+	u_int8_t	ip_hook[MAX_PACKET_CACHE];
+	int		packet_cache_write_index;
+};
+
+struct pack_cache packet_cache[HASHBUCKETS];
+void    init_packet_cache(void);
+u_int8_t	packet_hashfunction(u_int32_t addr);
+int		check_duplicate(u_int32_t source, u_int16_t id, 
+    u_int8_t hook);
+
+#endif /* MULTICAST_PACKET_CACHE_H */
+
diff -urNb aodv-uu-0.7.2/multicast_routing_table.c maodv-umd-0.7.2/multicast_routing_table.c
--- aodv-uu-0.7.2/multicast_routing_table.c	Wed Dec 31 19:00:00 1969
+++ maodv-umd-0.7.2/multicast_routing_table.c	Wed Jun 25 17:46:10 2003
@@ -0,0 +1,983 @@
+#ifdef MAODV
+
+/*****************************************************************************
+ *
+ * Copyright (C) 2003 CSHCN, University of Maryland.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Authors: Dionysus Blazakis <dblaze@umd.edu>
+ *          Jonathan Polley <jpolley@umd.edu>
+ *          Dan Rusk <drusk@umd.edu>
+ *          Manish Karir <karir@umd.edu>
+ *          Jonathan McGee <mcgee@umd.edu>
+ *
+ *****************************************************************************/
+
+#include <time.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <netinet/in.h>
+#include <netinet/igmp.h>
+
+#include "multicast_routing_table.h"
+
+#include "igmp.h"
+#include "aodv_timeout.h"
+#include "packet_queue.h"
+#include "aodv_rerr.h"
+#include "aodv_hello.h"
+#include "aodv_socket.h"
+#include "k_route.h"
+#include "k_mroute.h"
+#include "timer_queue.h"
+#include "defs.h"
+#include "debug.h"
+#include "params.h"
+#include "seek_list.h"
+#include "maodv_mact.h"
+#include "maodv_grph.h"
+
+static struct timer mrt_debug_timer;
+
+struct multicast_routing_table mrt_tbl;
+
+inline static unsigned int hashing(u_int32_t addr);
+
+/*
+   Local static functions
+*/
+
+/*
+   hashing( addr )
+   A VERY simple "hash" function.  Taskes the multicast address as 
+   a key and hacks off the most significant bits. (how many bits it 
+   masks off depends on the size of the hash table. look at the
+   MRT_TABLEMASK define) This becomes an index into the hash table.
+
+*/
+inline static unsigned int hashing(u_int32_t addr)
+{
+    return( addr & MRT_TABLEMASK );
+}
+
+/*
+ *  Public functions
+ */
+
+/*
+ *  mrt_table_init( )
+ *  Create an empty table with 0 entries.
+ */
+void mrt_table_init()
+{
+    int index;
+    int fd;
+
+    mrt_tbl.num_entries = 0;
+
+    /* init buckets with null pointers. */
+    for( index = 0; index < MRT_TABLESIZE; index++ ) {
+        mrt_tbl.tbl[index] = NULL;
+    }
+
+    /* CHECK: add in with other log code?  not yet... */
+
+    /* every 10 seconds? */
+    mrt_debug_timer.handler = (timeout_func_t) &mrt_table_dump;
+    mrt_debug_timer.data = NULL;
+
+    fd = open( "nh_log", O_RDWR | O_CREAT | O_TRUNC, S_IROTH |
+        S_IWUSR | S_IRUSR | S_IRGRP );
+
+    close ( fd );
+    
+    fd = open( "mrt_log", O_RDWR | O_CREAT | O_TRUNC, S_IROTH |
+        S_IWUSR | S_IRUSR | S_IRGRP );
+
+    close ( fd );
+
+    mrt_table_dump();
+}
+
+/*
+ *  mrt_table_destroy( )
+ *  Destroy table and each entry.
+ */
+void mrt_table_destroy()
+{
+    int index;
+    mrt_table_t *curr;
+    mrt_table_t *dead;
+
+    for( index = 0; index < MRT_TABLESIZE; index++ ) {
+        curr = mrt_tbl.tbl[index];
+
+        while( curr ) {
+            dead = curr;
+            curr = curr->next;
+
+            /*   TODO: Timeout multicast routes.
+            timer_remove( &dead->mrt_timer ); */
+
+            mrt_nexthop_remove_all( dead );
+
+            mrt_sources_remove_all( dead );
+            free( dead );
+        }
+
+        /* safety */
+        mrt_tbl.tbl[index] = NULL;
+    }
+
+    mrt_tbl.num_entries = 0;
+}
+
+/*
+ *  mrt_table_insert( route info )
+ *  This creates a route with NO next hop info.  Any next hop info must be 
+ *  added with other function calls.
+ */
+mrt_table_t *mrt_table_insert(u_int32_t grp_addr, u_int32_t grp_leader_addr,
+    u_int32_t grp_seqno,
+    unsigned int ifindex,
+    u_int8_t leader_hcnt,
+    u_int8_t is_member)
+{
+    mrt_table_t *new_entry;
+    int index;
+
+    /* if it's already in the table, we can't add it */
+    if ( mrt_table_find( grp_addr ) ) {
+        return NULL;
+    }
+
+    index = hashing( grp_addr );
+
+    new_entry = (mrt_table_t *) malloc( sizeof( mrt_table_t ) );
+    if ( !new_entry ) {
+        /* go down if theres no memory?  probably best idea */
+        fprintf( stderr, "multicast_routing_table.c: Cannot allocate memory for route.\n" );
+        exit( -1 );
+    }
+
+    new_entry->grp_addr = grp_addr;
+    new_entry->grp_leader_addr = grp_leader_addr;
+    new_entry->grp_seqno = grp_seqno;
+    new_entry->am_leader = 0;   /* false... i am not leader! */
+
+    new_entry->ifindex = ifindex;
+    new_entry->leader_hcnt = leader_hcnt;
+    new_entry->is_member = is_member;
+    new_entry->is_router = 0;    /* false */
+    new_entry->is_broken = 0;    /* false */
+    new_entry->in_repair = 0;    /* false */
+    new_entry->is_gateway = 0;   /* false */
+
+    /* initialize timers */
+
+    /*  TODO: Timeout routes.
+    new_entry->mrt_timer.handler = &multicast_route_expire_timeout;
+    new_entry->mrt_timer.data = new_entry; */
+
+    /* empty next hop list */
+    new_entry->nexthops = NULL;
+    new_entry->activated_upstream_cnt = 0;
+    new_entry->activated_downstream_cnt = 0;
+
+    new_entry->sources = NULL;
+    new_entry->origlist = NULL;
+
+    /* make me first, so next will be whoever is currently top of bucket */
+    new_entry->next = mrt_tbl.tbl[index];
+    mrt_tbl.tbl[index] = new_entry;
+    mrt_tbl.num_entries++;
+    /* CHECK: add kernel route entry */
+    
+    /* grph timer */
+    new_entry->grph_timer.handler=(timeout_func_t) &grph_send_callback;
+    new_entry->grph_timer.data=new_entry;
+
+    /* start new timer */
+
+    /*  TODO: Timeout routes.
+    DEBUG(LOG_INFO, 0, "New timer for %s, life=%d",
+          ip_to_str(new_entry->grp_addr), ACTIVE_ROUTE_TIMEOUT );
+
+    timer_set_timeout( &new_entry->mrt_timer, ACTIVE_ROUTE_TIMEOUT );
+    */
+
+    return new_entry;
+}
+
+/*
+ *  mrt_table_update_timeout( route, lifetime )
+ *  Resets the route timeout.  Renews the lease in the route table.
+ */
+NS_INLINE mrt_table_t *mrt_table_update_timeout(mrt_table_t * mrt,
+    u_int32_t lifetime)
+{
+    struct timeval new_timeout;
+
+    /* make sure route tp update is somewhat legal. */
+    if ( !mrt ) {
+        log(LOG_WARNING, 0, __FUNCTION__,
+            "Attempting to update NULL route.");
+
+        return NULL;
+    }
+
+    gettimeofday( &new_timeout, NULL );
+    timeval_add_msec( &new_timeout, lifetime );
+
+    /* TODO: Timeout routes.
+    if ( timeval_diff( &mrt->mrt_timer.timeout, &new_timeout ) < 0 ) {
+        timer_set_timeout( &mrt->mrt_timer, lifetime );
+    }
+    */
+
+    return mrt;
+}
+
+/*
+ *  mrt_table_find( group address )
+ *  This looks up an entry in the routing table.  If none is found,
+ *  NULL is returned.  Otherwise a pointer to the entry is returned.
+ */
+mrt_table_t *mrt_table_find(u_int32_t grp_addr)
+{
+    mrt_table_t *curr;
+    int index;
+
+    index = hashing( grp_addr );
+    curr = mrt_tbl.tbl[index];
+
+    /* If nothing is in the bucket the group address hashes to,
+       return NULL.  It's definitely not here. */
+    if ( !curr ) {
+        return NULL;
+    }
+
+    while( curr ) {
+        if ( curr->grp_addr == grp_addr ) {
+            break;
+        }
+
+        curr = curr->next;
+    }
+
+    return curr;
+}
+
+/*
+ *  mrt_table_delete( group addr )
+ *  Delete a route from the routing table.
+ */
+void mrt_table_delete(u_int32_t grp_addr)
+{
+    int index;
+    mrt_table_t * curr, * prev;
+
+    index = hashing( grp_addr );
+
+    curr = mrt_tbl.tbl[index];
+    prev = NULL;
+
+    if ( !curr ) {
+        log(LOG_WARNING, 0, __FUNCTION__,
+            "Attempting to delete an unknown route.");
+        return;
+    }
+
+    while( curr ) {
+        if ( curr->grp_addr == grp_addr ) {
+            break;
+        }
+
+        prev = curr;
+        curr = curr->next;
+    }
+
+    if ( !curr ) {
+        log(LOG_WARNING, 0, __FUNCTION__,
+            "Attempting to delete an unknown route.");
+        return;
+    }
+
+    /* CHECK: Remove entry from kernel routing table. */
+    /*  TODO: Timeout routes.
+    timer_remove( &curr->mrt_timer ); */
+
+    mrt_nexthop_remove_all( curr );
+
+    if ( !prev ) {
+        /* Deleting the head */
+        mrt_tbl.tbl[index] = NULL;
+    } else {
+        prev->next = curr->next;
+    }
+
+    mrt_tbl.num_entries--;
+
+    free( curr );
+}
+
+/*
+ *  mrt_nexthop_add( multi route, nh addr, direction )
+ *  Adds a nexthop entry into a routes information. Starts out unactivated.
+ */
+mrt_nexthop_t * mrt_nexthop_add(mrt_table_t * mrt, u_int32_t addr, 
+    u_int8_t direction, u_int32_t grp_seqno)
+{
+    mrt_nexthop_t *newhop;
+
+    if ( !mrt ) {
+        log(LOG_WARNING, 0, __FUNCTION__,
+            "Attempting to add a next hop to an unknown route.");
+        return NULL;
+    }
+
+    newhop = mrt_nexthop_find( mrt, addr );
+    if ( newhop ) {    /* if it's already there, update it? */
+        return newhop;
+    }
+
+    newhop = (mrt_nexthop_t *) malloc( sizeof( mrt_nexthop_t ) );
+    if ( !newhop ) {
+        fprintf( stderr, "multicast_routing_table.c: Error allocating nexthop entry.\n" );
+        exit( -1 );
+    }
+
+    newhop->addr = addr;
+    newhop->direction = direction;
+    newhop->activated = 0;    /* 0 == FALSE */
+    newhop->grp_hcnt = 0xff;  /* start with infinite hcnt */
+    newhop->grp_seqno=grp_seqno;
+
+    newhop->next = mrt->nexthops;
+    mrt->nexthops = newhop;
+
+    return newhop;
+}
+
+/*
+ *  mrt_nexthop_remove( route, addr )
+ *  Remove a nexthop entry from a kernel route info.
+ */
+void mrt_nexthop_remove(mrt_table_t * mrt, u_int32_t addr )
+{
+    mrt_nexthop_t * curr, * prev;
+
+    if ( !mrt ) {
+        log(LOG_WARNING, 0, __FUNCTION__,
+            "Attempting to remove a next hop from an unknown route.");
+        return;
+    }
+
+    curr = mrt->nexthops;
+    prev = NULL;
+
+    if ( !curr ) {
+        log(LOG_WARNING, 0, __FUNCTION__,
+            "Attempting to remove a next hop [%s] that doesn't exist.",
+             ip_to_str( addr ) );
+        return;
+    }
+
+    while( curr ) {
+        if ( curr->addr == addr ) {
+            break;
+        }
+
+        prev = curr;
+        curr = curr->next;
+    }
+
+    if ( !curr ) {
+        log(LOG_WARNING, 0, __FUNCTION__,
+            "Attempting to remove a next hop that doesn't exist.");
+        return;
+    }
+
+    mrt_nexthop_deactivate(mrt, addr);
+
+    if ( !prev ) {
+        mrt->nexthops = curr->next;
+    } else {
+        prev->next = curr->next;
+    }
+
+    free( curr );
+}
+
+/*
+ *  mrt_nexthop_activated( route, addr, on/off )
+ *  Sets a certain nexthop flag indicating if this route is active or not.
+ */
+void mrt_nexthop_activate(mrt_table_t * mrt, u_int32_t addr)
+{
+    FILE *nh_log;
+    mrt_nexthop_t *curr;
+
+    if ( !mrt ) {
+        log(LOG_WARNING, 0, __FUNCTION__,
+            "Attempting to activate a next hop for a NULL route.");
+        return;
+    }
+
+    curr = mrt->nexthops;
+
+    while( curr ) {
+        if ( curr->addr == addr ) {
+            break;
+        }
+
+        curr = curr->next;
+    }
+
+    if ( !curr ) {
+        log(LOG_WARNING, 0, __FUNCTION__,
+            "Attempting to activate a next hop that doesn't exist.");
+        return;
+    }
+
+    curr->activated = 1;
+
+    if ( curr->direction == MRT_UPSTREAM ) {
+        mrt->activated_upstream_cnt++;
+    } else if ( curr->direction == MRT_DOWNSTREAM ) {
+        mrt->activated_downstream_cnt++;
+    }
+    
+    nh_log=fopen("nh_log", "a");
+    fprintf(nh_log, "ACTIVATE: %x %x\n", mrt->grp_addr, addr);
+    fclose(nh_log);
+}
+
+/*
+ *  mrt_nexthop_deactivate( route, addr )
+ *  Sets a certain nexthop flag indicating if this route is active or not.
+ */
+void mrt_nexthop_deactivate(mrt_table_t * mrt, u_int32_t addr)
+{
+    FILE *nh_log;
+    mrt_nexthop_t *curr;
+
+    if ( !mrt ) {
+        log(LOG_WARNING, 0, __FUNCTION__,
+            "Attempting to activate a next hop for a NULL route.");
+        return;
+    }
+
+    curr = mrt->nexthops;
+
+    while( curr ) {
+        if ( curr->addr == addr ) {
+            break;
+        }
+
+        curr = curr->next;
+    }
+
+    if ( !curr ) {
+        log(LOG_WARNING, 0, __FUNCTION__,
+            "Attempting to deactivate a next hop that doesn't exist.");
+        return;
+    }
+
+    if(curr->activated == 1){
+        if ( curr->direction == MRT_UPSTREAM ) {
+            mrt->activated_upstream_cnt--;
+        } else if ( curr->direction == MRT_DOWNSTREAM ) {
+            mrt->activated_downstream_cnt--;
+        }
+
+        curr->activated=0;
+        
+        nh_log=fopen("nh_log", "a");
+        fprintf(nh_log, "DEACTIVATE: %x %x\n", mrt->grp_addr, addr);
+        fclose(nh_log);
+    }
+}
+
+/*
+ *  mrt_nexthop_get_upstream( table entry )
+ *  Returns pointer to activated upstream next hop.
+ */
+mrt_nexthop_t *mrt_table_get_activated_upstream(mrt_table_t * mrt)
+{
+    mrt_nexthop_t *curr;
+        
+    if ( !mrt ) { 
+        log(LOG_WARNING, 0, __FUNCTION__,
+            "Attempting to get an upstream for a NULL route.");
+        return NULL;
+    }
+        
+    curr = mrt->nexthops;
+
+    while( curr ) {
+        if ( ( curr->activated ) && ( curr->direction == MRT_UPSTREAM ) ) {
+            break;
+        }
+    
+        curr = curr->next;
+    }
+        
+    return curr;
+}
+
+/*
+ *  mrt_nexthop_remove_all( table entry )
+ *  Destroys every entry in next_hop list for a multicast route.
+ */
+void mrt_nexthop_remove_all(mrt_table_t * mrt)
+{
+    mrt_nexthop_t *curr, *dead;
+
+    curr = mrt->nexthops;
+
+    while( curr ) {
+        dead = curr;
+        curr = curr->next;
+
+        free( dead );
+    }
+
+    /* easier to debug if it's NULL instead of garbage */
+    mrt->nexthops = NULL;
+    mrt->activated_upstream_cnt = 0;
+    mrt->activated_downstream_cnt = 0;
+}
+
+/*
+ *  mrt_sources_find( table entry, source )
+ *  Finds an entry in source list for a multicast route.
+ */
+mrt_src_t *mrt_sources_find(mrt_table_t * mrt, u_int32_t src)
+{
+    mrt_src_t *curr;
+
+    if ( !mrt ) {
+        log(LOG_WARNING, 0, __FUNCTION__,
+            "Attempting to find a source to an unknown route.");
+        return NULL;
+    }
+
+    curr = mrt->sources;
+
+    while( curr ) {
+        if ( curr->src_addr == src ) {
+            break;
+        }
+
+        curr = curr->next;
+    }
+
+    return curr;
+}
+
+/*
+ *  mrt_sources_add( table entry, source )
+ *  Adds an entry in source list for a multicast route.
+ */
+void mrt_sources_add(u_int32_t src, u_int32_t dest)
+{
+    mrt_table_t *mrt;
+    mrt_src_t *newsrc;
+
+    mrt = mrt_table_find( dest );
+    if ( !mrt ) {
+        log(LOG_WARNING, 0, __FUNCTION__,
+            "Attempting to add a source to an unknown route.");
+        return;
+    }
+
+    newsrc = mrt_sources_find( mrt, src );
+    if ( newsrc ) {    /* if it's already there, update it? */
+        return;
+    }
+
+    newsrc = (mrt_src_t *) malloc( sizeof( mrt_src_t ) );
+    if ( !newsrc ) {
+        /* if no memory... quit */
+        fprintf( stderr, "multicast_routing_table.c: Error allocating source entry.\n" );
+        exit( -1 );
+    }
+
+    kernel_mrt_add_route( src, dest, 0 );
+
+    newsrc->src_addr = src;
+    newsrc->next = mrt->sources;
+    mrt->sources = newsrc;
+}
+
+/*
+ *  mrt_sources_remove_all( table entry )
+ *  Destroys every entry in source list for a multicast route.
+ */
+void mrt_sources_remove_all(mrt_table_t * mrt)
+{
+    mrt_src_t *curr, *dead;
+
+    curr = mrt->sources;
+
+    while( curr ) {
+        dead = curr;
+        curr = curr->next;
+
+        kernel_mrt_del_route( dead->src_addr, mrt->grp_addr, 0 );
+
+        free( dead );
+    }
+
+    /* easier to debug if it's NULL instead of garbage */
+    mrt->sources = NULL;
+}
+
+/*
+ *  mrt_origlist_find( table entry, orig )
+ *  Finds an entry in originator list for a multicast route.
+ */
+mrt_orig_t *mrt_origlist_find(mrt_table_t * mrt, u_int32_t orig)
+{
+    mrt_orig_t *curr;
+
+    if ( !mrt ) {
+        log(LOG_WARNING, 0, __FUNCTION__,
+            "Attempting to find a source to an unknown route.");
+        return NULL;
+    }
+
+    curr = mrt->origlist;
+
+    while( curr ) {
+        if ( curr->orig_addr == orig ) {
+            break;
+        }
+
+        curr = curr->next;
+    }
+
+    return curr;
+}
+
+/*
+ *  mrt_origlist_add( table entry, orig, seqno, hcnt )
+ *  Adds an entry in originator list for a multicast route.
+ */
+mrt_orig_t * mrt_origlist_add(mrt_table_t *mrt, u_int32_t orig )
+{
+    mrt_orig_t *neworig;
+
+    if ( !mrt ) {
+        log(LOG_WARNING, 0, __FUNCTION__,
+            "Attempting to add a source to an unknown route.");
+        return NULL;
+    }
+
+    neworig = mrt_origlist_find( mrt, orig );
+    if ( neworig ) {    /* if it's already there, update it? */
+        return neworig;
+    }
+
+    neworig = (mrt_orig_t *) malloc( sizeof( mrt_orig_t ) );
+    if ( !neworig ) {
+        fprintf( stderr, "multicast_routing_table.c: Error allocating orig entry.\n" );
+        exit( -1 );
+    }
+
+    neworig->orig_addr = orig;
+    neworig->grp_seqno = 0;
+    neworig->grp_hcnt = 0xff;
+    neworig->next = mrt->origlist;
+    neworig->up = mrt;
+    mrt->origlist = neworig;
+
+    /* do timeout stuff */
+    neworig->cleanup_timer.handler = (timeout_func_t) &mrt_origlist_remove;
+    neworig->cleanup_timer.data = neworig;
+    timer_set_timeout( &( neworig->cleanup_timer ), RREP_WAIT_TIME );
+
+    return neworig;
+}
+
+/*
+ *  mrt_origlist_remove( orig entry )
+ *  For the timeout callback.  Removes a single entry in the list.
+ */
+void mrt_origlist_remove(mrt_orig_t *entry)
+{
+    mrt_orig_t * curr = NULL, * prev = NULL;
+
+    DEBUG( LOG_DEBUG, 0, "In origlist timeout." );
+
+    if ( !entry ) {
+        log(LOG_WARNING, 0, __FUNCTION__,
+            "Attempting to remove a orig entry that didn't exist.");
+        return;
+    }
+
+    timer_remove( &( entry->cleanup_timer ) );
+
+    if ( !( entry->up ) ) {
+        log(LOG_WARNING, 0, __FUNCTION__,
+            "Attempting to remove a orig entry that didn't have a mrt.");
+        return;
+    }
+
+    prev = NULL;
+    curr = entry->up->origlist;
+
+    while( (curr) && (curr != entry) ) {
+        prev = curr;
+        curr = curr->next;
+    }
+
+    if ( prev == NULL ) {
+        if ( curr == NULL ) {
+            /* empty list */
+            DEBUG( LOG_DEBUG, 0, "Tried to remove from empty list." );
+            return;
+        } else {
+            /* first element remove */
+            DEBUG( LOG_DEBUG, 0, "Removed first element" );
+            entry->up->origlist = NULL;
+            free( entry );
+        }
+    } else {
+        if ( curr == NULL ) {
+            /* empty list */
+            DEBUG( LOG_DEBUG, 0, "Tried to remove an unknown entry." );
+            return;
+        } else {
+            /* somewhere in the middle or last element */
+            DEBUG( LOG_DEBUG, 0, "Removed middle or last element.");
+            prev->next = curr->next;
+            free( entry );
+        }
+    }
+}
+
+/*
+ *  mrt_table_set_leader( route, leader addr, leader hops )
+ *  Sets the leader and hopcount of a particular route entry (a multicast group).
+ */
+void mrt_table_set_leader(mrt_table_t * mrt, u_int32_t grp_leader_addr, u_int8_t leader_hcnt)
+{
+    if ( !mrt ) {
+        log(LOG_WARNING, 0, __FUNCTION__,
+            "Attempting to set the leader of a route that doesn't exist.");
+        return;
+    }
+
+    mrt->grp_leader_addr = grp_leader_addr;
+    mrt->leader_hcnt = leader_hcnt;
+}
+
+/*
+ *  mrt_table_set_leader_hcnt( route, leader hops )
+ *  Sets only the hopcount to the leader.  Leader remains the same.
+ */
+void mrt_table_set_leader_hopcount(mrt_table_t * mrt, u_int8_t leader_hcnt)
+{
+    if ( !mrt ) {
+        log(LOG_WARNING, 0, __FUNCTION__,
+            "Attempting to set the hop count of a route that doesn't exist.");
+        return;
+    }
+    
+    mrt->leader_hcnt = leader_hcnt;
+}
+
+/*
+ *  mrt_table_set_membership( route, boolean (memeber or not) )
+ *  Sets our flag true if we're a member of the group to which this is a route.
+ */
+void mrt_table_set_membership(mrt_table_t * mrt, u_int8_t ismember)
+{
+    if ( !mrt ) {
+        log(LOG_WARNING, 0, __FUNCTION__,
+            "Attempting to set membership of a route that doesn't exist.");
+        return;
+    }
+
+    mrt->is_member = ismember;
+}
+
+/*
+ *  mrt_table_dump( )
+ *  Prints the routing table  
+ */
+void mrt_table_dump(void)
+{
+    int index;
+    mrt_table_t * curr;
+    mrt_nexthop_t * hops;
+    mrt_orig_t * origs;
+    FILE *log;
+    struct timeval now;
+    struct tm *time;
+
+    log=fopen("mrt_log", "a");
+    if(log==NULL){
+        perror("mrt_table_dump");
+    }
+
+    /* reset timer */
+    timer_set_timeout( &( mrt_debug_timer ), 5000 );
+
+    gettimeofday(&now, NULL);
+    time = localtime(&now.tv_sec);
+
+    fprintf( log, "\n# Entries: %d       Time: %02d:%02d:%02d.%03ld\n", mrt_tbl.num_entries,
+          time->tm_hour, time->tm_min, time->tm_sec, now.tv_usec / 1000 );
+    for ( index = 0; index < MRT_TABLESIZE; index++ )
+    {
+        curr = mrt_tbl.tbl[index];
+        while ( curr ) {
+            fprintf( log, "\t* * * * * * * * * * * * * * *\n" );
+            fprintf( log, "\tGroup Addr[%s]\tLeader Addr[%s]\n",
+                ip_to_str( curr->grp_addr ),
+                ip_to_str( curr->grp_leader_addr ) );
+            fprintf( log, "\tSeq #[%d]\tLeader Hop Count[%d]\n",
+                curr->grp_seqno, curr->leader_hcnt );
+            fprintf( log, "\tMembership[%d]", curr->is_member );
+            fprintf( log, "\tRouter[%d]\tLeader[%d]\n", curr->is_router,
+                curr->am_leader );
+            fprintf( log, "\tBroken[%d]\tRepairing[%d]", curr->is_broken,
+                curr->in_repair );
+            fprintf( log, "\tGateway[%d]\n", curr->is_gateway );
+            fprintf( log, "\tAct. Up. Count[%d]\tAct. Down. Count[%d]\n", 
+                curr->activated_upstream_cnt,
+                curr->activated_downstream_cnt );
+            fprintf( log, "\tNext Hops\n" );
+            hops = curr->nexthops;
+            while( hops ) {
+                fprintf( log, "\t\t* * * * * * * *\n\t\tAddr[%s]\n",
+                    ip_to_str( hops->addr ) );
+                fprintf( log, "\t\tActivated[%d]\tDirection[%c]\n",
+                    hops->activated,
+                    ( ( hops->direction == MRT_UPSTREAM ) ? ( 'U' ) : ( 'D' ) ) );
+                fprintf( log, "\t\tGroup Hopcount[%d]\tGroup Seq#[%d]\n",
+                    hops->grp_hcnt, hops->grp_seqno );
+                hops = hops->next;
+            }
+		fprintf( log, "\tOriginator List\n" );
+	    origs = curr->origlist;
+	    while( origs ){
+	      fprintf( log, "\t\t* * * * * * * *\n\t\tAddr[%s]\n",
+		       ip_to_str( origs->orig_addr ) );
+	      fprintf( log, "\t\tOrig Hopcount[%d]\tOrig Seq#[%d]\n",
+		       origs->grp_hcnt, origs->grp_seqno );
+	      origs = origs->next;
+	    }
+            curr = curr->next;
+        }
+    }
+
+    fclose( log );
+}
+
+void mrt_table_become_leader(mrt_table_t *mrt){
+    int i=0;
+    /* CHECK: better way to select interface */
+    /* set first enabled interface's ip as the group leader ip */
+    for(i=0; i<MAX_NR_INTERFACES; i++){
+        if(this_host.devs[i].enabled){
+            mrt->grp_leader_addr=this_host.devs[i].ipaddr;
+        }
+    }
+    if(!mrt->is_gateway) {
+        mrt->is_member=1;
+    }
+    mrt->am_leader = 1; /* wahoo i'm now the REAL leader */
+    mrt->grp_seqno=0;
+    mrt->leader_hcnt=0;
+    mrt->grph_update_cnt=1;
+
+    /* mrt->is_router=1; */
+    mrt_table_start_routing(mrt);
+    
+    /* send a hello */
+    grph_send_callback(mrt);
+}
+
+mrt_nexthop_t *mrt_table_get_best_upstream(mrt_table_t *mrt){
+    mrt_nexthop_t *nexthop, *besthop=NULL;
+
+    nexthop=mrt->nexthops;
+
+    while(nexthop!=NULL) {
+        /* Before qualifying to be a upstream best hop, the next 
+           hop must first, in fact be upstream.
+           - if that is true, then the current nexthop will take the
+           besthop position if either:
+             - there is not current besthop
+             - sequence number is greater than curr besthop
+             - seq no are equal, but we have a lesser hop count
+        */ 
+        if(nexthop->direction == MRT_UPSTREAM &&
+            (besthop == NULL ||
+              (nexthop->grp_seqno > besthop->grp_seqno ||
+                (nexthop->grp_seqno == besthop->grp_seqno &&
+                  nexthop->grp_hcnt < besthop->grp_hcnt) ) ) ) {
+            besthop=nexthop;
+        }
+        nexthop=nexthop->next;
+    }
+
+    return besthop;
+}
+
+mrt_nexthop_t *mrt_nexthop_find(mrt_table_t *mrt, uint32_t addr){
+    mrt_nexthop_t *nexthop;
+
+    nexthop=mrt->nexthops;
+
+    while(nexthop!=NULL && nexthop->addr!=addr) {
+        nexthop=nexthop->next;
+    }
+
+    return nexthop;
+}
+
+void mrt_table_start_routing(mrt_table_t *mrt){
+    FILE *nh_log;
+    
+    mrt->is_router=1;
+
+    nh_log=fopen("nh_log", "a");
+    fprintf(nh_log, "JOIN: %x\n", mrt->grp_addr);
+    fclose(nh_log);
+
+    if(this_host.gateway_mode) {
+        /* If in gateway mode, notify multicast router */
+        mrt->is_gateway = 1;
+        igmp_sendreply(mrt, dev_indices[0]);
+    }
+}
+
+void mrt_table_stop_routing(mrt_table_t *mrt){
+    FILE *nh_log;
+    
+    mrt->is_router=0;
+
+    nh_log=fopen("nh_log", "a");
+    fprintf(nh_log, "LEAVE: %x\n", mrt->grp_addr);
+    fclose(nh_log);
+}
+
+#endif /* MAODV */
diff -urNb aodv-uu-0.7.2/multicast_routing_table.h maodv-umd-0.7.2/multicast_routing_table.h
--- aodv-uu-0.7.2/multicast_routing_table.h	Wed Dec 31 19:00:00 1969
+++ maodv-umd-0.7.2/multicast_routing_table.h	Wed Jun 25 17:46:10 2003
@@ -0,0 +1,153 @@
+/*****************************************************************************
+ *
+ * Copyright (C) 2003 CSHCN, University of Maryland.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Authors: Dionysus Blazakis <dblaze@umd.edu>
+ *          Jonathan Polley <jpolley@umd.edu>
+ *          Dan Rusk <drusk@umd.edu>
+ *          Manish Karir <karir@umd.edu>
+ *          Jonathan McGee <mcgee@umd.edu>
+ *
+ *****************************************************************************/
+
+#ifndef MULTICAST_ROUTING_TABLE_H
+#define MULTICAST_ROUTING_TABLE_H
+
+#ifndef NS_NO_GLOBALS
+#include "defs.h"
+
+typedef struct mrt_table mrt_table_t;
+
+#define MRT_UPSTREAM   1
+#define MRT_DOWNSTREAM 2
+
+/* struct for next hops */
+typedef struct _mrt_nexthop_t {
+    u_int32_t addr;
+    u_int8_t activated;
+    u_int8_t direction;
+    u_int8_t grp_hcnt;              /* only for use with upstream hops */
+    u_int32_t grp_seqno;            /* only for use with upstream hops */
+    struct _mrt_nexthop_t *next;
+} mrt_nexthop_t;
+
+typedef struct _mrt_src_t {
+    u_int32_t src_addr;
+    struct _mrt_src_t *next;
+} mrt_src_t;
+
+typedef struct _mrt_orig_t {
+    u_int32_t orig_addr;
+    u_int32_t grp_seqno;
+    u_int8_t grp_hcnt;
+    struct timer cleanup_timer;
+
+    mrt_table_t * up;
+    struct _mrt_orig_t * next;
+} mrt_orig_t;
+
+/* Route table entries */
+struct mrt_table {
+    u_int32_t grp_addr;
+    u_int32_t grp_leader_addr;
+    u_int32_t grp_seqno;
+    u_int8_t am_leader;            /* are we the group leader? */
+
+    unsigned int ifindex;
+    u_int8_t leader_hcnt;
+    u_int8_t is_member;
+    u_int8_t is_router;
+    u_int8_t is_broken;
+    u_int8_t in_repair;
+    u_int8_t is_gateway;
+
+    struct timer mrt_timer;
+    struct timer grph_timer;
+    struct timer mact_timer;     /* send mact to our upstream */
+    struct timer prune_timer;
+
+    mrt_nexthop_t *nexthops;
+    u_int8_t activated_upstream_cnt;
+    u_int16_t activated_downstream_cnt;
+
+    mrt_src_t * sources;
+    mrt_orig_t * origlist;
+
+    char grph_update_cnt;  /* for if the next grph is to be an update */
+
+    struct mrt_table *next;
+};
+
+
+#define MRT_TABLESIZE 64		/* Must be a power of 2 */
+#define MRT_TABLEMASK (MRT_TABLESIZE - 1)
+
+struct multicast_routing_table {
+    unsigned int num_entries;
+    mrt_table_t *tbl[MRT_TABLESIZE];
+};
+
+#endif				/* NS_NO_GLOBALS */
+
+#ifndef NS_NO_DECLARATIONS
+
+extern struct multicast_routing_table mrt_tbl;
+
+void mrt_table_init();
+void mrt_table_destroy();
+mrt_table_t *mrt_table_insert(u_int32_t grp_addr, u_int32_t grp_leader_addr,
+                              u_int32_t grp_seqno,
+                              unsigned int ifindex,
+                              u_int8_t leader_hcnt,
+                              u_int8_t is_member);
+
+NS_INLINE mrt_table_t *mrt_table_update_timeout(mrt_table_t * mrt,
+					      u_int32_t lifetime);
+mrt_table_t *mrt_table_find(u_int32_t grp_addr);
+void mrt_table_delete(u_int32_t grp_addr);
+mrt_nexthop_t *mrt_table_get_activated_upstream(mrt_table_t * mrt);
+mrt_nexthop_t *mrt_table_get_best_upstream(mrt_table_t *mrt);
+
+mrt_nexthop_t *mrt_nexthop_add(mrt_table_t * mrt, u_int32_t addr, 
+    u_int8_t direction, u_int32_t grp_seqno);
+void mrt_nexthop_remove(mrt_table_t * mrt, u_int32_t addr );
+void mrt_nexthop_activate(mrt_table_t * mrt, u_int32_t addr);
+void mrt_nexthop_deactivate(mrt_table_t * mrt, u_int32_t addr);
+void mrt_nexthop_remove_all(mrt_table_t * mrt);
+mrt_nexthop_t *mrt_nexthop_find(mrt_table_t *mrt, uint32_t addr);
+
+mrt_src_t *mrt_sources_find(mrt_table_t * mrt, u_int32_t src);
+void mrt_sources_add(u_int32_t src, u_int32_t dest);
+void mrt_sources_remove_all(mrt_table_t * mrt);
+
+mrt_orig_t * mrt_origlist_find(mrt_table_t *mrt, u_int32_t orig);
+mrt_orig_t * mrt_origlist_add(mrt_table_t *mrt, u_int32_t orig);
+void mrt_origlist_remove(mrt_orig_t *entry);
+
+void mrt_table_set_leader(mrt_table_t * mrt, u_int32_t grp_leader_addr, u_int8_t leader_hcnt);
+void mrt_table_set_leader_hopcount(mrt_table_t * mrt, u_int8_t leader_hcnt);
+void mrt_table_become_leader(mrt_table_t *mrt);
+
+void mrt_table_set_membership(mrt_table_t * mrt, u_int8_t ismember);
+void mrt_table_start_routing(mrt_table_t *mrt);
+void mrt_table_stop_routing(mrt_table_t *mrt);
+
+void mrt_table_dump(void);
+
+#endif				/* NS_NO_DECLARATIONS */
+
+#endif				/* MULTICAST_ROUTING_TABLE_H */
diff -urNb aodv-uu-0.7.2/packet_input.c maodv-umd-0.7.2/packet_input.c
--- aodv-uu-0.7.2/packet_input.c	Mon Jun  2 19:20:10 2003
+++ maodv-umd-0.7.2/packet_input.c	Fri Dec  5 17:42:32 2003
@@ -29,6 +29,18 @@
 #include <netinet/udp.h>
 #include <netinet/ip_icmp.h>
 
+/* SOCK_RAW refuses to cooperate... */
+#include <sys/socket.h>
+#include <features.h>    /* for the glibc version number */
+#if __GLIBC__ >= 2 && __GLIBC_MINOR >= 1
+#include <netpacket/packet.h>
+#include <net/ethernet.h>     /* the L2 protocols */
+#else
+#include <asm/types.h>
+#include <linux/if_packet.h>
+#include <linux/if_ether.h>   /* The L2 protocols */
+#endif
+
 #include "defs.h"
 #include "debug.h"
 #include "routing_table.h"
@@ -44,6 +56,12 @@
 #include "packet_queue.h"
 #include "packet_input.h"
 
+#ifdef MAODV
+#include "igmp.h"
+#include "multicast_routing_table.h"
+#include "multicast_packet_cache.h"
+#endif
+
 #define BUFSIZE 2048
 
 extern int internet_gw_mode, wait_on_reboot, optimized_hellos, llfeedback;
@@ -58,6 +76,24 @@
 /* Set this if you want lots of debug printouts: */
 /* #define DEBUG_PACKET */
 
+/* from 
+    "Internetworking with TCP/IP: Volume II"
+    Second Edition
+    Douglas E. Comer, David L. Stevens */
+static u_int16_t my_ip_csum( unsigned short *buf, int nshorts )
+{
+    u_int32_t sum;
+
+    for( sum = 0; nshorts > 0; nshorts-- ) {
+        sum += *buf++;
+    }
+
+    sum = ( sum >> 16 ) + ( sum & 0xffff );
+    sum += (sum >> 16 );
+    
+    return ~sum;
+} 
+
 #ifndef NS_PORT
 static void die(struct ipq_handle *h)
 {
@@ -104,11 +140,26 @@
 static void packet_input(int fd)
 #endif
 {
-    rt_table_t *fwd_rt, *rev_rt, *next_hop_rt, *expired_rt = NULL;
+    rt_table_t *fwd_rt = NULL, *rev_rt, *next_hop_rt, *expired_rt = NULL;
     u_int32_t dest_addr, src_addr;
     u_int8_t rreq_flags = 0;
     unsigned int ifindex;
     struct ip_data *ipd = NULL;
+#ifdef MAODV
+    /* This is to "hack" around the Linux UDP ip->id field which
+       remains zero unless you fragment a IP packet.  Not likely.
+
+       We just change the ip->id for each packet leaving
+       destined for a multicast address.  There is really no
+       other way to work this in Linux.  The source code states
+       that Linux was never intened to have a router + host for 
+       multicast IP. 
+
+       The ip-id is needed to cache multicast packets to avoid
+       flooding a multicast packet around the network for ttl
+       hops.  */
+    static u_int16_t staticid = 0;
+#endif
 
 #ifdef NS_PORT
     ifindex = NS_IFINDEX;	// Always use ns interface
@@ -164,10 +215,20 @@
 
     if (pkt->hook == 0)
 	dev_name = pkt->indev_name;
-    else if (pkt->hook == 3)
+    else if ((pkt->hook == 3) || (pkt->hook == 4))
 	dev_name = pkt->outdev_name;
-    else
+    else {
 	dev_name = NULL;
+    }
+
+    if (dev_name) {
+	ifindex = name2index(dev_name);
+	if (ifindex < 0) {
+	    DEBUG(LOG_ERR, 0, "name2index error!");
+	    ifindex = 0;
+	}
+    } else
+	ifindex = 0;
 
     /* We know from kaodv.c that this is an IP packet */
     ip = (struct iphdr *) pkt->payload;
@@ -200,28 +261,30 @@
 #endif
 
 	break;
+#ifdef MAODV
+    case IPPROTO_IGMP:
+        if(pkt->hook == 3) {
+            igmp_process((IGMP*)((char*)ip + (ip->ihl << 2)), ifindex);
+
+            /* drop the packet after processing */
+            status = ipq_set_verdict(h, pkt->packet_id, NF_DROP, 0, NULL);
+            if(status < 0)
+                die(h);
+            return;
+        }
+        break;
+#endif
     }
 
 #ifdef DEBUG_PACKET
     DEBUG(LOG_INFO, 0, "pkt to %s", ip_to_str(dest_addr));
 #endif
 
-    if (dev_name) {
-	ifindex = name2index(dev_name);
-	if (ifindex < 0) {
-	    DEBUG(LOG_ERR, 0, "name2index error!");
-	    return;
-	}
-    } else
-	ifindex = 0;
 #endif				/* NS_PORT */
 
     /* If the packet is not interesting we just let it go through... */
     if (dest_addr == AODV_BROADCAST ||
-	dest_addr == DEV_IFINDEX(ifindex).broadcast ||
-	((internet_gw_mode && this_host.gateway_mode)
-	 && ((dest_addr & DEV_IFINDEX(ifindex).netmask) !=
-	     DEV_IFINDEX(ifindex).broadcast))) {
+    	dest_addr == DEV_IFINDEX(ifindex).broadcast) {
 #ifdef NS_PORT
 	sendPacket(p, 0, 0.0);
 #else
@@ -230,8 +293,14 @@
     }
 
     /* Find the entry of the neighboring node and the destination  (if any). */
-    rev_rt = rt_table_find(src_addr);
     fwd_rt = rt_table_find(dest_addr);
+    /* If captured because of gateway mode, do not try to construct a
+     * reverse route. */
+    if((pkt->mark == 4) && (pkt->hook == 0)) {
+        rev_rt = NULL;
+    } else {
+        rev_rt = rt_table_find(src_addr);
+    }
 
     /* UPDATE TIMERS on active forward and reverse routes...  */
 
@@ -263,6 +332,155 @@
 	    rt_table_update_timeout(next_hop_rt, ACTIVE_ROUTE_TIMEOUT);
     }
 
+#ifdef MAODV
+    if(IN_MULTICAST(dest_addr)){
+        u_int8_t *pay;
+        u_int32_t size;
+        mrt_table_t *mrt=mrt_table_find(dest_addr);
+
+        if(mrt==NULL || (!mrt->is_router && DEV_IFINDEX(ifindex).ipaddr!=src_addr)){
+            /* we got a packet for which we have no entry */
+	    status = ipq_set_verdict(h, pkt->packet_id, NF_DROP, 0, NULL);
+	    if (status < 0)
+		die(h);
+            return;
+        }
+        /* note: this is like an else... note the return */
+
+        if ( (pkt->mark == 4) || this_host.gateway_mode) {
+            /* Gateway mode relays packets itself since it can't control the
+             * multicast routing tables.  */
+            if((!this_host.gateway_mode
+                        && src_addr == DEV_IFINDEX(ifindex).ipaddr)
+                    || (ip->id == 0)) {
+            /* from our LOCAL_OUT hook.  let's change the ip->id field */
+            staticid++;
+            ip->id = htons(staticid);
+
+            /* now recalculate the chksum... wahoo! */
+            /* CHECK: this could be more intelligent... */ 
+            ip->check = 0;
+            ip->check = my_ip_csum( (unsigned short *) ip, ip->ihl * 2 );
+            }
+        }
+
+        if(!mrt->is_router || mrt->is_broken ){
+            /* we have an invalid route, do discovery. */
+            size = pkt->data_len;
+            pay = (u_int8_t *) malloc( pkt->data_len );
+            if ( pay == NULL ) {
+                perror( "in packet_input for multicast local out buffer." );
+                exit( -1 );
+            }
+            memcpy( pay, pkt->payload, size );
+
+            rreq_flags = rreq_flags | RREQ_JOIN;
+            mcast_packet_queue_add(pkt->packet_id, dest_addr, size, pay);
+
+            check_duplicate( src_addr, ip->id, pkt->hook );
+
+            goto mcast_route_discovery;
+
+        }else{
+            /* route is valid, packet wants out, send the packet along its
+             * way */
+            if ( !check_duplicate( src_addr, ip->id, pkt->hook ) ) {
+                status = ipq_set_verdict(h, pkt->packet_id, NF_DROP, 0, NULL);
+                if (status < 0)
+                    die(h);
+                return;  
+            } else {
+                mrt_sources_add( src_addr, dest_addr );
+                mrt_table_update_timeout(mrt, ACTIVE_ROUTE_TIMEOUT);
+
+                /* In gateway mode, we need to duplicate the packet ourselves
+                 * since OSPF is handling the route table and we can't ask it
+                 * to duplicate on this interface. */
+                if(this_host.gateway_mode && (pkt->hook == 0) && (ip->ttl > 1)
+                        && (src_addr != DEV_IFINDEX(ifindex).ipaddr)) {
+                    /* The injection of raw ip packets when a multicast route
+                     * exists for the destination appears broken.  This is a
+                     * workaround until a better solution can be found. */
+#if 1
+                    int sock = socket(PF_PACKET, SOCK_DGRAM, htonl(ETH_P_IP));
+                    struct sockaddr_ll sll;
+
+                    /* Decrement TTL, since the raw socket will recalculate
+                     * the IP checksum, don't worry about it */
+                    ip->ttl--;
+                    ip->check = 0;
+                    ip->check = my_ip_csum((unsigned short *) ip, ip->ihl * 2);
+
+                    /* Repeat packet */
+                    memset(&sll, 0, sizeof(sll));
+                    sll.sll_family = AF_PACKET;
+                    sll.sll_addr[0] = 1;
+                    sll.sll_addr[1] = 0;
+                    sll.sll_addr[2] = 0x5E;
+                    sll.sll_addr[3] = (dest_addr >> 16) & 0x7F;
+                    sll.sll_addr[4] = (dest_addr >> 8) & 0xFF;
+                    sll.sll_addr[5] = (dest_addr & 0xFF);
+                    sll.sll_halen = 6;
+                    sll.sll_ifindex = ifindex;
+                    sll.sll_protocol = htons(ETH_P_IP);
+                    if(sendto(sock, pkt->payload, pkt->data_len, 0,
+                                (struct sockaddr*)&sll, sizeof(sll)) < 0) {
+                        printf("ifindex = %d, devname = %s\n", ifindex, dev_name);
+                        perror("send_raw");
+                    }
+
+                    /* Reincrement the checksum so we don't have a bad
+                     * checksum or drop the packet. */
+                    ip->ttl++;
+                    ip->check = 0;
+                    ip->check = my_ip_csum((unsigned short *) ip, ip->ihl * 2);
+                    close(sock);
+#else /* #if 0 */
+                    /* This was an attempt at using the raw IP facilities to
+                     * repeat the IP packets.  Somewhere in the Linux IP
+                     * stack it was improperly clobbering the source IP.  This
+                     * only occured when a route for the multicast group
+                     * appeared in the multicast routing table. */
+                    int sock = socket(PF_INET, SOCK_RAW, IPPROTO_RAW);
+                    struct sockaddr_in sin;
+                    int flag;
+
+                    /* Decrement TTL, since the raw socket will recalculate
+                     * the IP checksum, don't worry about it */
+                    ip->ttl--;
+                    flag = -1;
+                    setsockopt(sock, SOL_IP, IP_HDRINCL, &flag, sizeof(flag));
+                    /* Repeat packet */
+                    memset(&sin, 0, sizeof(sin));
+                    sin.sin_family = AF_INET;
+                    sin.sin_port = ip->protocol;
+                    sin.sin_addr.s_addr = htonl(src_addr);
+                    if(sendto(sock, pkt->payload, pkt->data_len, MSG_DONTROUTE,
+                                    (struct sockaddr*)&sin, sizeof(sin)) < 0) {
+                            perror("send_raw");
+                    }
+
+                    /* Reincrement the checksum so we don't have a bad
+                     * checksum or drop the packet. */
+                    ip->ttl++;
+                    close(sock);
+#endif /* #if 0 */
+                }
+
+                status = ipq_set_verdict( h, pkt->packet_id, NF_ACCEPT,
+                        pkt->data_len, pkt->payload);
+                if(status < 0)
+                    die(h);
+
+                /* we did our own accept! */
+                /* goto accept; */
+                return;
+            }
+            /***** never gets here... look above ****/
+        }
+    }
+#endif
+
     /* OK, the timeouts have been updated. Now see if either: 1. The
        packet is for this node -> ACCEPT. 2. The packet is not for this
        node -> Send RERR (someone want's this node to forward packets
@@ -271,6 +489,13 @@
     /* If the packet is destined for this node, then just accept it. */
     if (dest_addr == DEV_IFINDEX(ifindex).ipaddr)
 	goto accept;
+    /* If in gateway mode and packet is headed to a different subnet, see
+     * if we have a wired route for it */
+    if (this_host.gateway_mode && ((dest_addr & DEV_IFINDEX(ifindex).netmask)
+            != (DEV_IFINDEX(ifindex).ipaddr & DEV_IFINDEX(ifindex).netmask))) {
+        if(get_route_metric(htonl(dest_addr)) != -1)
+            goto accept;
+    }
 
     if (!fwd_rt || fwd_rt->state == INVALID ||
 	(fwd_rt->hcnt == 1 && (fwd_rt->flags & RT_UNIDIR))) {
@@ -290,10 +515,10 @@
 #else
 #define PACKET_IS_INBOUND pkt->hook == 0
 #endif
-	if (PACKET_IS_INBOUND) {
-
+	if (PACKET_IS_INBOUND && (pkt->mark != 4)) {
 	    u_int32_t rerr_dest;
 	    RERR *rerr;
+
 #ifdef NS_PORT
 	    DEBUG(LOG_DEBUG, 0,
 		  "No route, src=%s dest=%s prev_hop=%s - DROPPING!",
@@ -347,6 +572,10 @@
 #else
 	packet_queue_add(pkt->packet_id, dest_addr);
 
+#ifdef MAODV
+       mcast_route_discovery:
+#endif /* MAODV */
+
 	/* Already seeking the destination? Then do not allocate any
 	   memory or generate a RREQ. */
 	if (seek_list_find(dest_addr))
@@ -370,7 +599,7 @@
 	if (fwd_rt && (fwd_rt->flags & RT_REPAIR))
 	    rreq_local_repair(expired_rt, src_addr, ipd);
 	else
-	    rreq_route_discovery(dest_addr, rreq_flags, ipd);
+	    rreq_route_discovery(dest_addr, rreq_flags, ipd, 0);
 
 	return;
 
diff -urNb aodv-uu-0.7.2/packet_queue.c maodv-umd-0.7.2/packet_queue.c
--- aodv-uu-0.7.2/packet_queue.c	Tue May 27 10:41:15 2003
+++ maodv-umd-0.7.2/packet_queue.c	Wed Jun 25 17:46:10 2003
@@ -34,6 +34,10 @@
 #include "timer_queue.h"
 #include "aodv_timeout.h"
 
+#ifdef MAODV
+#include "multicast_routing_table.h"
+#endif
+
 extern struct ipq_handle *h;
 
 #endif
@@ -69,6 +73,9 @@
 #else
 	ipq_set_verdict(h, qp->id, NF_DROP, 0, NULL);
 #endif				/* NS_PORT */
+    if(qp->payload != NULL) {
+        free(qp->payload);
+    }
 	free(qp);
 	count++;
     }
@@ -96,6 +103,9 @@
 	    ipq_set_verdict(h, qp->id, NF_DROP, 0, NULL);
 #endif				/* NS_PORT */
 
+        if(qp->payload) {
+            free(qp->payload);
+        }
 	    free(qp);
 	    count++;
 	    PQ.len--;
@@ -108,6 +118,7 @@
     
     return count;
 }
+
 /* Buffer a packet in a FIFO queue. Implemented as a linked list,
    where we add elements at the end and remove at the beginning.... */
 
@@ -153,6 +164,9 @@
 #endif
     qp->dest_addr = dest_addr;
     
+    qp->payload = NULL;
+    qp->size = 0;
+
     gettimeofday(&qp->q_time, NULL);
     
     list_add_tail(&PQ.head, &qp->l);
@@ -168,6 +182,43 @@
 #endif
 }
 
+void mcast_packet_queue_add(unsigned long id, u_int32_t dest_addr,
+    u_int32_t s, u_int8_t *pay)
+{
+    struct q_pkt *qp;
+
+    if (PQ.len >= MAX_QUEUE_LENGTH) {
+    DEBUG(LOG_DEBUG, 0, "MAX Queue length reached. Removing first pkt in queue");
+    if(!list_empty(&PQ.head)) {
+        qp = (struct q_pkt *)PQ.head.next;
+
+        list_detach(PQ.head.next);
+        ipq_set_verdict(h, qp->id, NF_DROP, 0, NULL);
+        PQ.len--;
+        if ( qp->payload )
+            free( qp->payload );
+        free(qp);
+    }
+    }
+
+    if ((qp = (struct q_pkt *) malloc(sizeof(struct q_pkt))) == NULL) {
+	fprintf(stderr, "Malloc failed!\n");
+	exit(-1);
+    }
+
+    qp->id = id;
+    qp->dest_addr = dest_addr;
+
+    qp->payload = pay;
+    qp->size = s;
+
+    gettimeofday(&qp->q_time, NULL);
+    list_add_tail(&PQ.head, &qp->l);
+
+    PQ.len++;
+}
+
+
 int NS_CLASS packet_queue_drop(u_int32_t dest_addr)
 {
     int count = 0;
@@ -183,6 +234,9 @@
 #else
 	    ipq_set_verdict(h, qp->id, NF_DROP, 0, NULL);
 #endif
+        if(qp->payload != NULL) {
+            free(qp->payload);
+        }
 	    free(qp);
 	    count++;
 	    PQ.len--;
@@ -226,7 +280,9 @@
 #else
 	    ipq_set_verdict(h, qp->id, NF_ACCEPT, 0, NULL);
 #endif				/* NS_PORT */
-	   
+	    if(qp->payload) {
+            DEBUG(LOG_DEBUG, 0, "Sent a multicast queued packet from wrong function.");
+        }
 	    free(qp);
 	    count++;
 	    PQ.len--;
@@ -249,3 +305,59 @@
 
     return count;
 }
+
+#ifdef MAODV
+
+int NS_CLASS mcast_packet_queue_send(u_int32_t dest_addr)
+{
+    int count = 0;
+    list_t *pos, *tmp;
+    mrt_table_t *mrt;
+#ifdef NS_PORT
+    double delay = 0;
+#define ARP_DELAY 0.005
+#endif
+
+    mrt = mrt_table_find(dest_addr);
+
+    if (!mrt || !mrt->is_router )
+	return -1;
+   
+    list_foreach_safe(pos, tmp, &PQ.head) {
+    struct q_pkt *qp = (struct q_pkt*)pos;
+
+	if (qp->dest_addr == dest_addr) {
+        list_detach(pos);
+	    ipq_set_verdict(h, qp->id, NF_ACCEPT, qp->size, 
+                qp->payload);
+
+        if ( qp->payload ) {
+            free( qp->payload );
+        }
+	    free(qp);
+	    count++;
+	    PQ.len--;
+	}
+    }
+
+    /* Update rt timeouts */
+    if (dest_addr != DEV_IFINDEX(mrt->ifindex).ipaddr) {
+        /* TODO: CHECK: Update multicast route table timer. */
+	/* rt_table_update_timeout(rt, ACTIVE_ROUTE_TIMEOUT); */
+
+        /*
+	next_hop_rt = rt_table_find(rt->next_hop);
+
+	if (next_hop_rt && next_hop_rt->state == VALID && 
+	    next_hop_rt->dest_addr != rt->dest_addr)
+	    rt_table_update_timeout(next_hop_rt, ACTIVE_ROUTE_TIMEOUT);
+        */
+    }
+
+    DEBUG(LOG_INFO, 0, "SENT %d packets to %s qlen=%u",
+	  count, ip_to_str(dest_addr), PQ.len);
+
+    return count;
+}
+
+#endif /* MAODV */
diff -urNb aodv-uu-0.7.2/packet_queue.h maodv-umd-0.7.2/packet_queue.h
--- aodv-uu-0.7.2/packet_queue.h	Thu May 22 19:11:35 2003
+++ maodv-umd-0.7.2/packet_queue.h	Thu Jul 17 18:03:51 2003
@@ -26,7 +26,7 @@
 #include "defs.h"
 #include "list.h"
 
-#define MAX_QUEUE_LENGTH 100
+#define MAX_QUEUE_LENGTH 20
 #define MAX_QUEUE_TIME 10000 /* Maximum time packets can be queued (ms) */
 #define GARBAGE_COLLECT_TIME 1000 /* Interval between running the
 				   * garbage collector (ms) */
@@ -40,6 +40,8 @@
 #else
     unsigned long id;
 #endif
+    u_int8_t * payload;
+    u_int32_t size;
 };
 
 struct packet_queue {
@@ -58,6 +60,11 @@
 #else
 void packet_queue_add(unsigned long id, u_int32_t dest_addr);
 #endif
+
+int mcast_packet_queue_send(u_int32_t dest_addr);
+void mcast_packet_queue_add(unsigned long id, u_int32_t dest_addr,
+    u_int32_t s, u_int8_t *pay);
+
 void packet_queue_init();
 void packet_queue_destroy();
 int packet_queue_drop(u_int32_t dest_addr);
diff -urNb aodv-uu-0.7.2/params.h maodv-umd-0.7.2/params.h
--- aodv-uu-0.7.2/params.h	Mon Nov 11 11:57:21 2002
+++ maodv-umd-0.7.2/params.h	Wed Jun 25 17:46:10 2003
@@ -33,12 +33,12 @@
 #define DELETE_PERIOD           ACTIVE_ROUTE_TIMEOUT
 #else
 /* HELLO messages are used: */
-#define ACTIVE_ROUTE_TIMEOUT    3000
+#define ACTIVE_ROUTE_TIMEOUT    3500
 #define DELETE_PERIOD           K * max(ACTIVE_ROUTE_TIMEOUT, ALLOWED_HELLO_LOSS * HELLO_INTERVAL)
 #define TTL_START               2
 #endif
 
-#define ALLOWED_HELLO_LOSS      2
+#define ALLOWED_HELLO_LOSS      3
 /* If expanding ring search is used, BLACKLIST_TIMEOUT should be?: */
 #define BLACKLIST_TIMEOUT       RREQ_RETRIES * NET_TRAVERSAL_TIME + (TTL_THRESHOLD - TTL_START)/TTL_INCREMENT + 1 + RREQ_RETRIES
 #define HELLO_INTERVAL          1000
@@ -57,5 +57,10 @@
 #define TIMEOUT_BUFFER          2
 #define TTL_INCREMENT           2
 #define TTL_THRESHOLD           7
+
+/* MAODV params */
+#define GROUP_HELLO_INTERVAL    5000
+#define RREP_WAIT_TIME          10000
+#define PRUNE_TIMEOUT           2 * RREP_WAIT_TIME
 
 #endif
diff -urNb aodv-uu-0.7.2/routing_table.c maodv-umd-0.7.2/routing_table.c
--- aodv-uu-0.7.2/routing_table.c	Tue May 27 12:32:58 2003
+++ maodv-umd-0.7.2/routing_table.c	Wed Jun 25 17:46:10 2003
@@ -39,6 +39,8 @@
 #include "seek_list.h"
 #endif				/* NS_PORT */
 
+#include <assert.h>
+
 static unsigned int hashing(u_int32_t * addr, hash_value * hash);
 
 #ifndef NS_PORT
@@ -156,6 +158,8 @@
     
     rt_tbl.num_entries++;
     
+    /* trying to track weird route bug */
+    assert(!(dest_addr == DEV_NR(0).ipaddr == next));	
 
     DEBUG(LOG_INFO, 0, "Inserting %s (bucket %d) next hop %s",
 	  ip_to_str(dest_addr), index, ip_to_str(next));
diff -urNb aodv-uu-0.7.2/seek_list.c maodv-umd-0.7.2/seek_list.c
--- aodv-uu-0.7.2/seek_list.c	Thu May 22 19:11:35 2003
+++ maodv-umd-0.7.2/seek_list.c	Wed Jun 25 17:46:10 2003
@@ -47,7 +47,9 @@
 seek_list_t *NS_CLASS seek_list_insert(u_int32_t dest_addr,
 				       u_int32_t dest_seqno,
 				       int ttl, u_int8_t flags,
-				       struct ip_data *ipd)
+				       struct ip_data *ipd,
+                                       u_int16_t grp_hcnt,
+                                       u_int32_t grp_addr )
 {
     seek_list_t *entry;
 
@@ -62,6 +64,8 @@
     entry->reqs = 0;
     entry->ttl = ttl;
     entry->ipd = ipd;
+    entry->grp_hcnt = grp_hcnt;
+    entry->grp_addr = grp_addr;
     entry->seek_timer.handler = &NS_CLASS route_discovery_timeout;
     entry->seek_timer.data = entry;
 
@@ -72,6 +76,32 @@
     return entry;
 }
 
+#ifdef MAODV
+int NS_CLASS seek_list_remove_mcast(u_int32_t dest_addr, u_int32_t grp_addr)
+{
+    list_t *pos;
+
+    list_foreach(pos, &seekhead) {
+	seek_list_t *entry = (seek_list_t *)pos;
+
+	if ((entry->dest_addr == dest_addr) && (entry->grp_addr == grp_addr)) {
+    	list_detach(&entry->l);
+
+        /* Make sure any timers are removed */
+        timer_remove(&entry->seek_timer);
+
+        if (entry->ipd)
+            free(entry->ipd);
+	    
+        free(entry);
+        return 1;
+    }
+    }
+
+	return 0;
+}
+#endif
+
 int NS_CLASS seek_list_remove(seek_list_t *entry)
 {
     if (!entry)
@@ -101,6 +131,27 @@
     }
     return NULL;
 }
+
+#ifdef MAODV
+/* note: This function call seems misleading at first because
+   most of the time a multicast RREQ should be destined for
+   a group, but tree merge is destined for the leader and contains
+   the group information in an extension. */
+seek_list_t *NS_CLASS seek_list_find_mcast(u_int32_t dest_addr, 
+    u_int32_t grp_addr)
+{
+    list_t *pos;
+
+    list_foreach(pos, &seekhead) {
+	seek_list_t *entry = (seek_list_t *)pos;
+
+	if ((entry->dest_addr == dest_addr) && (entry->grp_addr == grp_addr)) {
+	    return entry;
+    }
+    }
+    return NULL;
+}
+#endif
 
 #ifdef SEEK_LIST_DEBUG
 void NS_CLASS seek_list_print()
diff -urNb aodv-uu-0.7.2/seek_list.h maodv-umd-0.7.2/seek_list.h
--- aodv-uu-0.7.2/seek_list.h	Thu May 22 19:11:35 2003
+++ maodv-umd-0.7.2/seek_list.h	Wed Jun 25 17:46:10 2003
@@ -44,15 +44,25 @@
     u_int8_t flags;		/* The flags we are using for resending the RREQ */
     int reqs;
     int ttl;
+    u_int16_t grp_hcnt;
+    u_int32_t grp_addr;
     struct timer seek_timer;
 } seek_list_t;
 #endif				/* NS_NO_GLOBALS */
 
 #ifndef NS_NO_DECLARATIONS
 seek_list_t *seek_list_insert(u_int32_t dest_addr, u_int32_t dest_seqno,
-			      int ttl, u_int8_t flags, struct ip_data *ipd);
+			      int ttl, u_int8_t flags, struct ip_data *ipd,
+                  u_int16_t grp_hcnt, u_int32_t grp_addr);
 int seek_list_remove(seek_list_t *entry);
 seek_list_t *seek_list_find(u_int32_t dest_addr);
+
+#ifdef MAODV
+seek_list_t *seek_list_find_mcast(u_int32_t dest_addr,
+    u_int32_t grp_addr);
+int NS_CLASS seek_list_remove_mcast(u_int32_t dest_addr,
+    u_int32_t grp_addr);
+#endif
 
 #ifdef NS_PORT
 #ifdef SEEK_LIST_DEBUG
