#if defined(MULTICAST)
/*
 * Internet Group Management Protocol (IGMP) as per RFC 1112.
 * 
 *	This protocol is to allow multicast routers to establish group
 * membership on attached networks. Thus allowing the router to not send 
 * data that is not needed.
 *
 * Jim Martin
 * Rutgers University - RUCS-TD/NS
 * jim@noc.rutgers.edu
 * 6/9/93
 */

#include "wattcp.h"
#include "stdlib.h"
#include "copyright.h"

typedef struct _pkt {
	in_Header	in;
	IGMP_packet	igmp;
};

static int igmp_id = 0;

/* 
 * igmp_handler - handles the incoming IGMP packets
 *
 * void igmp_handler( in_Header *ip )
 * Where:
 *	ip	is the IP packet in question
 *
 * Returns: None
 *
 */

void igmp_handler( ip )
in_Header *ip;
{
	IGMP_packet     *igmp;
	word		len;
	byte		i;
	longword	host;

	len = in_GetHdrlenBytes(ip);
	igmp = (IGMP_packet *)((byte *)ip + len);


	/* If it doesn't check, drop it */
	if ( checksum(igmp, 8) != 0xffff ){
		return;
	}

	/* Get this out of the way right up front */

	host = intel( igmp->address );

	/* first determine whether this is a report or a query */
	switch (igmp->type){
		case( IGMP_Query ):
			for( i = 0 ; i < IPMULTI_SIZE ; i++){
				if(_ipmulti[i].active &&
				   (_ipmulti[i].ina != ALL_SYSTEMS) &&
				   ( !_ipmulti[i].replytime )){
				      _ipmulti[i].replytime = time(NULL)
				   	                     + random(11);
				   }
			}
			break;
		case( IGMP_Report ):
			for( i = 0 ; i < IPMULTI_SIZE ; i++){
				if( _ipmulti[i].active &&
				    (_ipmulti[i].ina == host) &&
				    ( host != ALL_SYSTEMS )){
					_ipmulti[i].replytime = 0;
					break;
				    }
			}
			break;
		default:
			break;
	}
}



/* 
 * igmp_report - send a IGMP Report packet
 *
 * int igmp_report( longword ina)
 * Where:
 *	ina	is the IP address to report.
 *
 * Returns:
 *	0	if unable to send report
 *	1	report was sent successfully
 */

int igmp_report( ina )
longword ina;
{
	struct _pkt  *pkt;
	in_Header *ip;
	IGMP_packet *igmp;
	eth_address	ethaddr;


	/* get the ethernet addr of the destination */
	multi_to_eth( (longword)ALL_SYSTEMS, ethaddr);

        /* format the packet with the request's hardware address */
        pkt = (struct _pkt*)(_eth_formatpacket( ethaddr, 8));

	/* make things a bit easier to work with */
	ip = &pkt->in;
	igmp = &pkt->igmp;

	/* first fill in the igmp packet */
	igmp->type = IGMP_Report;
	igmp->version = IGMP_Version;
	igmp->mbz = 0;
	igmp->checksum = 0;
	igmp->address = intel( ina );

	/* then compute the IGMP checksum */
	igmp->checksum = ~checksum(igmp, sizeof( IGMP_packet ));

	/* Now to stick it in an IP packet */
	ip->ver = 4;
	ip->hdrlen = 5;
	ip->length = intel16( sizeof( in_Header ) + sizeof( IGMP_packet) );
	ip->tos = 0;
	ip->identification = intel16 (igmp_id ++);
/*	ip->frag = 0; */
	ip->ttl = 1;
	ip->proto = IGMP_PROTO;
	ip->checksum = 0;
	ip->source = intel( my_ip_addr );
	ip->destination = intel( ina );
	ip->checksum = ~checksum(ip, sizeof( in_Header ));

	_eth_send( intel16( ip->length ));
	return(1);
}
#endif /* MULTICAST */
