#if defined(MULTICAST)
/*
 * IP Multicasting extensions as per RFC 1112.
 * 
 *	These extensions include routines to detect multicast addresses,
 * transform Multicast IP addresses to Multicast Ethernet addresses, as
 * well as a mechanism to join and leave multicast groups.
 *
 * Jim Martin
 * Rutgers University - RUCS-TD/NS
 * jim@noc.rutgers.edu
 * 6/6/93
 */

#include "wattcp.h"
#include "copyright.h"

multicast _ipmulti[IPMULTI_SIZE];

/* 
 * is_multicast - determines if the given IP addr is Class D (Multicast)
 *
 * int is_multicast( longword ina )
 * Where:
 *	ina	IP address in question
 * Returns:
 *	1	if ina is Class D
 *	0	if ina is not Class D
 */

int is_multicast( ina )
longword ina;
{
	if ( (ina & CLASS_D_MASK) == CLASS_D_MASK )
		return( 1 );
	else
		return( 0 );
}

/* 
 * multi_to_eth - calculates the proper ethernet address for a given
 *                IP Multicast address.
 *
 * int multi_to_eth( longword ina, eth_address *ethaddr )
 * Where:
 *	ina	IP address to be converted
 *	ethaddr	Ethernet MAC address
 * Returns:
 *	1	if calculation is successful
 *	0	if calculation failed
 */

int multi_to_eth( ina, ethaddr )
longword ina;
eth_address ethaddr;
{
	longword top = ETH_MULTI;

	ina = ( ina & IPMULTI_MASK );
	ethaddr[0] = ( top >> 16 );
	ethaddr[1] = (( top >> 8 ) & 0xff);
	ethaddr[2] = ( top & 0xff );
	ethaddr[3] = ( ina >> 16 );
	ethaddr[4] = (( ina >> 8 ) & 0xff );
	ethaddr[5] = ( ina & 0xff );
	return( 1 );
}


/* 
 * join_mcast_group - joins a multicast group
 *
 * int join_mcast_group( longword ina )
 * Where:
 *	ina	IP address of the group to be joined
 * Returns:
 *	1	if the group was joined successfully
 *	0	if attempt failed
 */

int join_mcast_group( ina )
longword ina;
{
	byte	i;
	int	free = -1;

	/* first verify that it's a valid mcast address */
	if ( ! is_multicast( ina ))
		return( 0 );

	/* determine if the group has already been joined */
	/* as well as what the first free slot is */
	for( i = 0; i < IPMULTI_SIZE ; i++){
		if( _ipmulti[i].active && (ina == _ipmulti[i].ina) ){
			_ipmulti[i].processes++;
			return( 1 );
		}
		if( ( free == -1 ) && ( ! _ipmulti[i].active ) )
			free = i;
	}

	/* alas, no...we need to join it */

	if( free == -1 )	/* out of slots! */
		return( 0 );

	_ipmulti[free].ina = ina;
	if ( ! _eth_join_mcast_group( free ))
		return( 0 );
	return( 1 );
}

/* 
 * leave_mcast_group - leaves a multicast group
 *
 * int leave_mcast_group( longword ina )
 * Where:
 *	ina	IP address of the group to be joined
 * Returns:
 *	1	if the group was left successfully
 *	0	if attempt failed
 */

int leave_mcast_group( ina )
longword ina;
{
	byte	i;
	int	groupnum = -1;

	/* first verify that it's a valid mcast address */
	if ( ! is_multicast( ina ))
		return( 0 );

	/* determine if the group has more than one interested
	   process. if so, then just decrement .processes and return */
	for( i = 0; i < IPMULTI_SIZE ; i++){
		if( _ipmulti[i].active && (ina == _ipmulti[i].ina)){
			if (_ipmulti[i].processes > 1 ){
				_ipmulti[i].processes--;
				return( 1 );
			}
			else {
				groupnum = i;
				break;
			}
		}
	}

	/* did the ipaddr they gave match anything in _ipmulti ?? */
	if ( groupnum == -1 )
		return( 0 );

	/* alas...we need to physically leave it */

	if ( ! _eth_leave_mcast_group( groupnum ))
		return( 0 );

	return( 1 );
}
#endif /* MULTICAST */
