diff --git a/drivers/rtl8139.c b/drivers/rtl8139.c
index afe1a4f..1ca4a89 100644
--- a/drivers/rtl8139.c
+++ b/drivers/rtl8139.c
@@ -535,4 +535,29 @@ static void rtl_disable(struct eth_device *dev)
 		udelay (100); /* wait 100us */
 	}
 }
+#ifdef RFC2090	/* Multicast TFTP ? */
+rtl_bcast_addr (struct eth_device *dev, u8 bcast_mac, u8 set)
+{
+ unsigned mc_filter[2], bits, i;
+
+	ioaddr = dev->iobase;
+	/* pick up status quo filters and mode */
+	mc_filter[0] = inl(ioaddr + MAR0 + 0);
+	mc_filter[1] = inl(ioaddr + MAR0 + 4);
+	rx_mode = inl(ioaddr + RxConfig);
+	/* Calc crc for mcast mac */
+	bits = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26;
+	i = (bits >> 5);
+	if (set)
+		mc_filter[i] |= 1 << (bits & 31);
+	else
+		mc_filter[i] &= ~(1 << (bits & 31));
+	if (mc_filter[0]|mc_filter[1])
+		rx_mode |= AcceptMulticast;
+	/* update regs */
+	outl(rx_mode, ioaddr + RxConfig);
+	outl(mc_filter[i], ioaddr + MAR0 + (i*4));
+}
+#endif /* RFC2090 Multicast TFTP ? */
+
 #endif	/* CFG_CMD_NET && CONFIG_NET_MULTI && CONFIG_RTL8139 */
diff --git a/drivers/tsec.c b/drivers/tsec.c
index 3f11eb0..7030109 100644
--- a/drivers/tsec.c
+++ b/drivers/tsec.c
@@ -378,6 +378,28 @@ uint mii_parse_sr(uint mii_reg, struct tsec_private * priv)
 		priv->link = 1;
 	}
 
+	/* take a stab at 10/100  and Duplex info too; from linux mii.c */
+	mii_reg = (read_phy_reg(priv, PHY_ANAR) &  read_phy_reg(priv, PHY_ANLPAR));
+	if ( mii_reg & PHY_ANLPAR_TXFD ) {
+		priv->duplexity = 1;
+		priv->speed = 100;
+	}
+	else if ( mii_reg & PHY_ANLPAR_TX ) {
+		priv->duplexity = 0;
+		priv->speed = 100;
+	}
+	else if ( mii_reg & PHY_ANLPAR_TX ) {
+		priv->duplexity = 0;
+		priv->speed = 100;
+	}
+	else if ( mii_reg & PHY_ANLPAR_10FD ) {
+		priv->duplexity = 1;
+		priv->speed = 10;
+	} else {
+		priv->duplexity = 0;
+		priv->speed = 10;
+	}
+
 	return 0;
 }
 
@@ -1056,6 +1078,26 @@ struct phy_info phy_info_VSC8244 = {
 			   {miim_end,}
 			   },
 };
+/* a generic flavor.  */
+struct phy_info phy_info_generic =  {
+	0,
+	"Unknown/Generic PHY",
+	32,
+	(struct phy_cmd[]) { /* config */
+		{PHY_BMCR, PHY_BMCR_RESET, NULL},
+		{PHY_BMCR, PHY_BMCR_AUTON|PHY_BMCR_RST_NEG, NULL},
+		{miim_end,}
+	},
+	(struct phy_cmd[]) { /* startup */
+		{PHY_BMSR, miim_read, NULL},
+		{PHY_BMSR, miim_read, &mii_parse_sr},
+		{miim_end,}
+	},
+	(struct phy_cmd[]) { /* shutdown */
+		{miim_end,}
+	}
+};
+
 
 struct phy_info phy_info_dm9161 = {
 	0x0181b88,
@@ -1203,6 +1245,7 @@ struct phy_info *phy_info[] = {
 	&phy_info_lxt971,
 	&phy_info_VSC8244,
 	&phy_info_dp83865,
+	&phy_info_generic,
 	NULL
 };
 
@@ -1382,4 +1425,47 @@ static int tsec_miiphy_write(char *devname, unsigned char addr,
 #endif /* defined(CONFIG_MII) || (CONFIG_COMMANDS & CFG_CMD_MII)
 		&& !defined(BITBANGMII) */
 
+#ifdef RFC2090	/* Multicast TFTP ? */
+
+/* CREDITS: linux gianfar driver, slightly adjusted... thanx. */
+
+/* Set the appropriate hash bit for the given addr */
+
+/* The algorithm works like so:
+ * 1) Take the Destination Address (ie the multicast address), and
+ * do a CRC on it (little endian), and reverse the bits of the
+ * result.
+ * 2) Use the 8 most significant bits as a hash into a 256-entry
+ * table.  The table is controlled through 8 32-bit registers:
+ * gaddr0-7.  gaddr0's MSB is entry 0, and gaddr7's LSB is
+ * gaddr7.  This means that the 3 most significant bits in the
+ * hash index which gaddr register to use, and the 5 other bits
+ * indicate which bit (assuming an IBM numbering scheme, which
+ * for PowerPC (tm) is usually the case) in the tregister holds
+ * the entry. */
+static int
+tsec_bcast_addr (struct eth_device *dev, u8 bcast_mac, u8 set)
+{
+ struct tsec_private *priv = privlist[1];
+ volatile tsec_t *regs = priv->regs;
+ volatile u32  *reg_array, value;
+ u8 result, whichbit, whichreg;
+
+	result = (u8)((ether_crc(MAC_ADDR_LEN,bcast_mac) >> 24) & 0xff);
+	whichbit = result & 0x1f;	/* the 5 LSB = which bit to set */
+	whichreg = result >> 5;		/* the 3 MSB = which reg to set it in */
+	value = (1 << (31-whichbit));
+
+	reg_array = &(regs->hash.gaddr0);
+
+	if (set) {
+		reg_array[whichreg] |= value;
+	} else {
+		reg_array[whichreg] &= ~value;
+	}
+	return;
+}
+#endif /* RFC2090 Multicast TFTP ? */
+
+
 #endif /* CONFIG_TSEC_ENET */
diff --git a/include/net.h b/include/net.h
index 461e038..c1ee8ee 100644
--- a/include/net.h
+++ b/include/net.h
@@ -102,7 +102,9 @@ struct eth_device {
 	int  (*send) (struct eth_device*, volatile void* pachet, int length);
 	int  (*recv) (struct eth_device*);
 	void (*halt) (struct eth_device*);
-
+#ifdef RFC2090
+	int (*mcast) (struct eth_device*, u32 ip, u8 set);
+#endif
 	struct eth_device *next;
 	void *priv;
 };
@@ -124,6 +126,10 @@ extern int eth_rx(void);			/* Check for received packets	*/
 extern void eth_halt(void);			/* stop SCC			*/
 extern char *eth_get_name(void);		/* get name of current device	*/
 
+#ifdef RFC2090
+void eth_mcast_join( IPaddr_t mcast_addr, u8 join);
+#endif
+
 
 /**********************************************************************/
 /*
@@ -168,6 +174,7 @@ typedef struct {
 #define PROT_VLAN	0x8100		/* IEEE 802.1q protocol		*/
 
 #define IPPROTO_ICMP	 1	/* Internet Control Message Protocol	*/
+#define IPPROTO_IGMP	 2	/* Internet Group Management Protocol   */
 #define IPPROTO_UDP	17	/* User Datagram Protocol		*/
 
 /*
diff --git a/net/eth.c b/net/eth.c
index 0fc2211..8780b1d 100644
--- a/net/eth.c
+++ b/net/eth.c
@@ -369,6 +369,51 @@ void eth_set_enetaddr(int num, char *addr) {
 
 	memcpy(dev->enetaddr, enetaddr, 6);
 }
+#ifdef RFC2090
+/* Multicast.
+ * mcast_addr: multicast ipaddr from which multicast Mac is made
+ * join: 1=join, 0=leave
+ */
+void eth_mcast_join( IPaddr_t mcast_ip, u8 join)
+{
+ u8 mcast_mac[6];
+	if (!eth_current || !eth_current->mcast)
+		return -1;
+	mcast_mac[5] = htonl(mcast_ip) & 0xff;
+	mcast_mac[4] = (htonl(mcast_ip)>>8) & 0xff;
+	mcast_mac[3] = (htonl(mcast_ip)>>16) & 0x7f;
+	mcast_mac[2] = 0x5e;
+	mcast_mac[1] = 0x0;
+	mcast_mac[0] = 0x1;
+	return eth_current->mcast(eth_current, mcast_mac, join);
+}
+
+/* the 'way' for ethernet-CRC-32. Spliced in from Linux lib/crc32.c 
+ * and this is the ethernet-crc method needed for TSEC -- and perhaps some 
+ * other adapter -- hash tables
+ */
+#define CRCPOLY_LE 0xedb88320
+u32 ether_crc (size_t len, unsigned char const *p)
+{
+	int i;
+	u32 crc;
+	crc = ~0;
+	while (len--) {
+		crc ^= *p++;
+		for (i = 0; i < 8; i++)
+			crc = (crc >> 1) ^ ((crc & 1) ? CRCPOLY_LE : 0);
+	}
+	/* an reverse the bits, cuz of way they arrive -- last-first */
+	crc = (crc >> 16) | (crc << 16);
+	crc = (crc >> 8 & 0x00ff00ff) | (crc << 8 & 0xff00ff00);
+	crc = (crc >> 4 & 0x0f0f0f0f) | (crc << 4 & 0xf0f0f0f0);
+	crc = (crc >> 2 & 0x33333333) | (crc << 2 & 0xcccccccc);
+	crc = (crc >> 1 & 0x55555555) | (crc << 1 & 0xaaaaaaaa);
+	return crc;
+}
+
+#endif
+
 
 int eth_init(bd_t *bis)
 {
diff --git a/net/net.c b/net/net.c
index 2ff7bfc..3f39add 100644
--- a/net/net.c
+++ b/net/net.c
@@ -118,6 +118,10 @@ char		NetOurHostName[32]={0,};	/* Our hostname			*/
 char		NetOurRootPath[64]={0,};	/* Our bootpath			*/
 ushort		NetBootFileSize=0;		/* Our bootfile size in blocks	*/
 
+#ifdef RFC2090	/* Multicast TFTP */
+IPaddr_t Mcast_addr;
+#endif
+
 /** END OF BOOTP EXTENTIONS **/
 
 ulong		NetBootFileXferSize;	/* The actual transferred size of the bootfile (in bytes) */
@@ -1386,6 +1390,9 @@ NetReceive(volatile uchar * inpkt, int len)
 		}
 		tmp = NetReadIP(&ip->ip_dst);
 		if (NetOurIP && tmp != NetOurIP && tmp != 0xFFFFFFFF) {
+#ifdef RFC2090	/* Multicast TFTP ? */
+			if (Mcast_addr != tmp)
+#endif
 			return;
 		}
 		/*
@@ -1492,6 +1499,7 @@ NetReceive(volatile uchar * inpkt, int len)
 		}
 #endif
 
+
 #ifdef CONFIG_NETCONSOLE
 		nc_input_packet((uchar *)ip +IP_HDR_SIZE,
 						ntohs(ip->udp_dst),
diff --git a/net/tftp.c b/net/tftp.c
index f3a5471..73f8064 100644
--- a/net/tftp.c
+++ b/net/tftp.c
@@ -61,6 +61,31 @@ static char *tftp_filename;
 extern flash_info_t flash_info[];
 #endif
 
+#ifdef RFC2090	/* Multicast TFTP */
+#include <malloc.h>
+/* 8k bit map .. 8k blocks is 16M.. max?? */
+#define MTFTP_MAXBLOCKS	0x2000
+static unsigned *Bitmap;
+static int PrevBitmapHole ;
+static uchar MasterClient=0;
+static uchar Multicast=0;
+// static int tftp_find_bitmap_hole(void);
+static void parse_multicast_oack(char *pkt,int len);
+extern IPaddr_t Mcast_addr;
+static int Mcast_port;
+static ulong TftpEndingBlock; /* .. I can get 'last' block before done..*/
+
+static void
+mcast_cleanup()
+{
+	if (Mcast_addr) eth_mcast_join(Mcast_addr, 0);
+	if (Bitmap) free(Bitmap);
+	Bitmap=NULL;
+	Mcast_addr = Multicast = Mcast_port = 0;
+	TftpEndingBlock = -1;
+}
+#endif	/* RFC2090 */
+
 static __inline__ void
 store_block (unsigned block, uchar * src, unsigned len)
 {
@@ -90,6 +115,11 @@ store_block (unsigned block, uchar * src, unsigned len)
 	{
 		(void)memcpy((void *)(load_addr + offset), src, len);
 	}
+#ifdef RFC2090
+	if (Multicast)
+		ext2_set_bit(block, Bitmap);
+		//Bitmap[(block)/32] |= (1 << ((block) % 32));
+#endif
 
 	if (NetBootFileXferSize < newsize)
 		NetBootFileXferSize = newsize;
@@ -108,6 +138,11 @@ TftpSend (void)
 	int			len = 0;
 	volatile ushort *s;
 
+#ifdef RFC2090	
+	/* Multicast TFTP.. non-MasterClients do not ACK data. */
+	if (Multicast && (TftpState == STATE_DATA) && (MasterClient == 0)) 
+		return;
+#endif
 	/*
 	 *	We will always be sending some sort of packet, so
 	 *	cobble together the packet headers now.
@@ -128,10 +163,15 @@ TftpSend (void)
 		strcpy ((char *)pkt, "timeout");
 		pkt += 7 /*strlen("timeout")*/ + 1;
 		sprintf((char *)pkt, "%d", TIMEOUT);
+		pkt += strlen((char *)pkt) + 1;
 #ifdef ET_DEBUG
 		printf("send option \"timeout %s\"\n", (char *)pkt);
 #endif
-		pkt += strlen((char *)pkt) + 1;
+#ifdef RFC2090	
+		pkt += sprintf((char *)pkt,"multicast");
+		*pkt++ = '\0';
+		*pkt++ = '\0';
+#endif /* RFC2090 */
 		len = pkt - xp;
 		break;
 
@@ -178,6 +218,7 @@ TftpHandler (uchar * pkt, unsigned dest, unsigned src, unsigned len)
 	ushort proto;
 	ushort *s;
 
+
 	if (dest != TftpOurPort) {
 		return;
 	}
@@ -208,6 +249,13 @@ TftpHandler (uchar * pkt, unsigned dest, unsigned src, unsigned len)
 #endif
 		TftpState = STATE_OACK;
 		TftpServerPort = src;
+#ifdef RFC2090
+		parse_multicast_oack((char *)pkt,len-1);
+		if ((Multicast) && (!MasterClient)) {
+			TftpState = STATE_DATA;	/* non-master just listens */
+			break;
+		}
+#endif
 		TftpSend (); /* Send ACK */
 		break;
 	case TFTP_DATA:
@@ -233,13 +281,11 @@ TftpHandler (uchar * pkt, unsigned dest, unsigned src, unsigned len)
 				puts ("\n\t ");
 			}
 		}
-
 #ifdef ET_DEBUG
 		if (TftpState == STATE_RRQ) {
 			puts ("Server did not acknowledge timeout option!\n");
 		}
 #endif
-
 		if (TftpState == STATE_RRQ || TftpState == STATE_OACK) {
 			/* first block received */
 			TftpState = STATE_DATA;
@@ -248,6 +294,12 @@ TftpHandler (uchar * pkt, unsigned dest, unsigned src, unsigned len)
 			TftpBlockWrap = 0;
 			TftpBlockWrapOffset = 0;
 
+#ifdef RFC2090
+			if (Multicast) { /* ..happens commonly if mcast */
+printf ("Starting midstream at block %d\n",TftpBlock);
+				TftpLastBlock = TftpBlock - 1;
+			} else
+#endif
 			if (TftpBlock != 1) {	/* Assertion */
 				printf ("\nTFTP error: "
 					"First block is not block 1 (%ld)\n"
@@ -257,7 +309,6 @@ TftpHandler (uchar * pkt, unsigned dest, unsigned src, unsigned len)
 				break;
 			}
 		}
-
 		if (TftpBlock == TftpLastBlock) {
 			/*
 			 *	Same block again; ignore it.
@@ -274,8 +325,34 @@ TftpHandler (uchar * pkt, unsigned dest, unsigned src, unsigned len)
 		 *	Acknoledge the block just received, which will prompt
 		 *	the server for the next one.
 		 */
+#ifdef RFC2090
+		/* if I am the MasterClient, actively calculate what my next needed
+ 		 * block is; else I'm passive; not ACKING 
+ 		 */
+		if (Multicast) {
+			if (len < TFTP_BLOCK_SIZE) 
+				TftpEndingBlock = TftpBlock;
+			else if (MasterClient) {
+				TftpBlock = PrevBitmapHole =
+				ext2_find_next_zero_bit(Bitmap,MTFTP_MAXBLOCKS,PrevBitmapHole);
+					//TftpLastBlock = TftpBlock = tftp_find_bitmap_hole();
+if (TftpBlock < TftpLastBlock) printf ("back; get missing from %d\n",TftpBlock);
+				TftpLastBlock = TftpBlock;
+			}
+		}
+#endif
 		TftpSend ();
 
+#ifdef RFC2090
+		if (Multicast) {
+			if (MasterClient && (TftpBlock >= TftpEndingBlock)) {
+				puts ("\nMulticast tftp done\n");
+				mcast_cleanup();
+				NetState = NETLOOP_SUCCESS;
+			} 
+		}
+		else
+#endif
 		if (len < TFTP_BLOCK_SIZE) {
 			/*
 			 *	We received the whole thing.  Try to
@@ -290,6 +367,9 @@ TftpHandler (uchar * pkt, unsigned dest, unsigned src, unsigned len)
 		printf ("\nTFTP error: '%s' (%d)\n",
 					pkt + 2, ntohs(*(ushort *)pkt));
 		puts ("Starting again\n\n");
+#ifdef RFC2090
+		mcast_cleanup();
+#endif
 		NetStartAgain ();
 		break;
 	}
@@ -301,6 +381,9 @@ TftpTimeout (void)
 {
 	if (++TftpTimeoutCount > TIMEOUT_COUNT) {
 		puts ("\nRetry count exceeded; starting again\n");
+#ifdef RFC2090
+		mcast_cleanup();
+#endif
 		NetStartAgain ();
 	} else {
 		puts ("T ");
@@ -370,6 +453,7 @@ TftpStart (void)
 	TftpState = STATE_RRQ;
 	/* Use a pseudo-random port unless a specific port is set */
 	TftpOurPort = 1024 + (get_timer(0) % 3072);
+
 #ifdef CONFIG_TFTP_PORT
 	if ((ep = getenv("tftpdstp")) != NULL) {
 		TftpServerPort = simple_strtol(ep, NULL, 10);
@@ -382,8 +466,141 @@ TftpStart (void)
 
 	/* zero out server ether in case the server ip has changed */
 	memset(NetServerEther, 0, 6);
+#ifdef RFC2090	/* Multicast TFTP */
+    mcast_cleanup();
+#endif
 
 	TftpSend ();
 }
 
+#ifdef RFC2090	/* Multicast TFTP */
+/* Credits: atftp project.
+ */
+
+/* pick up BcastAddr, Port, and whether I am [now] the master-client. *
+ * Frame:
+ *    +-------+-----------+---+-------~~-------+---+
+ *    |  opc  | multicast | 0 | addr, port, mc | 0 |
+ *    +-------+-----------+---+-------~~-------+---+
+ * The multicast addr/port becomes what I listen to, and if 'mc' is '1' then
+ * I am the new master-client so must send ACKs to DataBlocks.  If I am not
+ * master-client, I'm a passive client, gathering what DataBlocks I may and
+ * making note of which ones I got in my bitmask.
+ * In theory, I never go from master->passive..
+ * .. this comes in with pkt already pointing just past opc
+ */
+static void parse_multicast_oack(char *pkt, int len)
+{
+ int i;
+ IPaddr_t addr;
+ char *mc_adr, *port, *mc, *e;
+
+	mc_adr=port=mc=NULL;
+	/* march along looking for 'multicast\0', which has to start at least
+	 * 14 bytes back from the end.
+	 */
+	for (i=0;i<len-14;i++)
+		if (strcmp (pkt+i,"multicast") == 0)
+			break;
+	if (i >= (len-14)) {
+		printf ("non-Multicast OACK, ign.\n");
+		return;
+	}
+	i+=10; /* strlen multicast */
+	mc_adr = pkt+i;
+	for (;i<len;i++) {
+		if (*(pkt+i) == ',') {
+			*(pkt+i) = '\0';
+			if (port) {
+				mc=pkt+i+1;
+				break;
+			} else {
+				port = pkt+i+1;
+			}
+		}
+	}
+	if (!port || !mc_adr || !mc ) return;
+	/* ..I now accept packets destined for this MCAST addr */
+	if (Multicast) {
+		if (MasterClient)
+			printf ("I was master now %s\n",mc?"master":"passive");
+		else
+			printf ("I was passive now %s\n",mc?"master":"passive");
+	} else {
+		if (Bitmap) { 
+			printf ("BUGBUGBUG Dave! why is this set!\n");
+			free(Bitmap);
+		}
+		if (!(Bitmap = malloc (MTFTP_MAXBLOCKS))) {
+			printf ("OH NO! No Bitmap!\n");
+			return;
+		}
+		memset (Bitmap,0,MTFTP_MAXBLOCKS);
+		PrevBitmapHole = -1;
+		Multicast = 1;
+	}
+	addr = string_to_ip(mc_adr);
+	if (Mcast_addr != addr) {
+		if (Mcast_addr)
+			eth_mcast_join(Mcast_addr, 0);
+		eth_mcast_join(Mcast_addr=addr, 1);
+	}
+	MasterClient = (unsigned char)simple_strtoul((char *)mc,&e,10);
+	Mcast_port = htons((unsigned short)simple_strtoul(port,&e,10));
+
+	printf ("Multicast: %s:%d [%d]\n", mc_adr, Mcast_port, MasterClient);
+	return;
+}
+
+#if 0
+/*
+ * Find a hole in the file bitmap.  We only do this when we are the MasterClient
+ * and once we are the MasterClient we remain so until done.. I.e. we start from
+ * PrevBitmapHole=-1 and march along till all the holes are full, up to when
+ * we request the last (or after) block
+ */
+static int tftp_find_bitmap_hole()
+{
+     int next_hole, next_word_no, next_bit_no;
+     unsigned int next_word;
+
+     /* initial stuff */
+     next_hole = PrevBitmapHole + 1;
+     next_word_no = next_hole / 32;
+     next_bit_no  = next_hole % 32;
+     next_word = Bitmap[next_word_no];
+    
+     /* Check if there is a remainder of the current word to traverse */
+     if (next_bit_no != 0)
+     {
+          /* traverse remainder of word. We know that all previous
+             bits are set */
+          if (next_word == 0xffffffff)
+          {
+               next_bit_no = 0;
+               next_word_no++;
+               next_word = Bitmap[next_word_no];
+          }
+     }
+    
+     /* travserse whole words */
+     while ((next_word == 0xffffffff) && (next_word_no < NB_BLOCK))
+     {
+          next_word_no++;
+          next_word = Bitmap[next_word_no];
+     }
+    
+     /* find the bit */
+     next_word >>= next_bit_no;
+     while (next_word & 1)
+     {
+         next_bit_no++;
+         next_word >>= 1;
+     }
+     return (PrevBitmapHole = (next_word_no * 32) + next_bit_no);
+}
+#endif
+
+#endif /* Multicast TFTP */
+
 #endif /* CFG_CMD_NET */
