0
mirror of https://github.com/Indemsys/Frequency_Inverter.git synced 2026-05-09 06:12:58 +00:00
Files
2022-01-04 12:22:53 +02:00

420 lines
11 KiB
C

/**HEADER********************************************************************
*
* Copyright (c) 2008 Freescale Semiconductor;
* All Rights Reserved
*
* Copyright (c) 2004-2008 Embedded Access Inc.;
* All Rights Reserved
*
* Copyright (c) 1989-2008 ARC International;
* All Rights Reserved
*
***************************************************************************
*
* THIS SOFTWARE IS PROVIDED BY FREESCALE "AS IS" AND ANY EXPRESSED OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL FREESCALE OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*
**************************************************************************
*
* $FileName: igmputil.c$
* $Version : 3.8.6.0$
* $Date : Jun-14-2012$
*
* Comments:
*
* This file contains the implementation of the Internet
* Group Management Protocol. For more details, refer
* to RFC1112 for version 1 and RFC2236 for version 2.
*
*END************************************************************************/
#include <rtcs.h>
#include "rtcs_prv.h"
#include "tcpip.h"
#include "ip_prv.h"
#if RTCSCFG_ENABLE_IGMP && RTCSCFG_ENABLE_IP4
/*
** Warning: IGMP is OPTIONAL. The functions below (most notably
** IGMP_ipif_add, IGMP_ipif_bind, IGMP_ipif_unbind_nosock
** and IGMP_is_member) may be called without a prior call
** to IGMP_init.
*/
uint_32 IGMP_join_if_local (IP_IF_PTR, ip_mreq _PTR_);
uint_32 IGMP_leave_if_local (IP_IF_PTR, MC_MEMBER_PTR _PTR_);
uint_32 IGMP_ipif_unbind_nosock (IP_IF_PTR, _ip_address);
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : IGMP_filter_add
* Returned Values : uint_32
* Comments :
* add a IGMP_filter in the physical interface
*
*END*-----------------------------------------------------------------*/
uint_32 IGMP_filter_add
(
IP_IF_PTR ipif,
_ip_address group_ip
)
{ /* Body */
if (!ipif->DEVICE.JOIN) {
return RTCS_OK;
} /* Endif */
/* join the group on the physical interface */
return ipif->DEVICE.JOIN(ipif, group_ip);
} /* Endbody */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : IGMP_filter_rm
* Returned Values : uint_32
* Comments :
* remove a IGMP_filter in the physical interface
*
*END*-----------------------------------------------------------------*/
uint_32 IGMP_filter_rm
(
IP_IF_PTR ipif,
_ip_address group_ip
)
{ /* Body */
if (!ipif->DEVICE.LEAVE) {
return RTCS_OK;
} /* Endif */
/* leave the group on the physical interface */
return ipif->DEVICE.LEAVE(ipif, group_ip);
} /* Endbody */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : IGMP_member_find
* Returned Values : MC_MEMBER_PTR
* Comments :
* look for a given group through a list of joined group
*
*END*-----------------------------------------------------------------*/
MC_MEMBER_PTR _PTR_ IGMP_member_find
(
MC_MEMBER_PTR _PTR_ phead,
ip_mreq _PTR_ igrp
)
{ /* Body */
for (; *phead ; phead = &(*phead)->NEXT) {
if ((*phead)->IGRP.imr_multiaddr.s_addr == igrp->imr_multiaddr.s_addr
&& (*phead)->IGRP.imr_interface.s_addr == igrp->imr_interface.s_addr) {
/* the group is already joined */
return phead;
} /* Endif */
} /* Endfor */
return NULL;
} /* Endbody */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : IGMP_member_create
* Returned Values : MC_MEMBER_PTR
* Comments :
* add a new group in a list
*
*END*-----------------------------------------------------------------*/
MC_MEMBER_PTR _PTR_ IGMP_member_create
(
MC_MEMBER_PTR _PTR_ phead,
ip_mreq _PTR_ igrp
)
{ /* Body */
IP_CFG_STRUCT_PTR IP_cfg_ptr = RTCS_getcfg(IP);
MC_MEMBER_PTR group;
group = RTCS_part_alloc_zero(IP_cfg_ptr->MCB_PARTID);
if (!group) {
return NULL;
} /* Endif */
group->IGRP = *igrp;
group->UCOUNT = 1;
group->NEXT = *phead;
*phead = group;
return phead;
} /* Endbody */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : IGMP_member_delete
* Returned Values : uint_32
* Comments :
* remove a group from a list
*
*END*-----------------------------------------------------------------*/
uint_32 IGMP_member_delete
(
MC_MEMBER_PTR _PTR_ pmember
)
{ /* Body */
MC_MEMBER_PTR group;
group = *pmember;
*pmember = group->NEXT;
RTCS_part_free(group);
return RTCS_OK;
} /* Endbody */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : IGMP_join_if_local
* Returned Values : uint_32
* Comments :
* join a local group on a given interface
*
*END*-----------------------------------------------------------------*/
uint_32 IGMP_join_if_local
(
IP_IF_PTR ipif, /* [IN] the interface descriptor */
ip_mreq _PTR_ igrp /* [IN] the group description */
)
{ /* Body */
MC_MEMBER_PTR _PTR_ pgroup;
uint_32 status;
/* join the group */
pgroup = IGMP_member_create(&ipif->IGMP_MEMBER, igrp);
if (!pgroup) {
return RTCSERR_IGMP_GROUP_ALLOC;
} /* Endif */
/* join the group on the physical interface */
status = IGMP_filter_add(ipif, igrp->imr_multiaddr.s_addr);
if (status != RTCS_OK) {
IGMP_member_delete(pgroup);
return status;
} /* Endif */
return RTCS_OK;
} /* Endbody */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : IGMP_leave_if_local
* Returned Values : uint_32
* Comments :
* leave the group on a given interface
*
*END*-----------------------------------------------------------------*/
uint_32 IGMP_leave_if_local
(
IP_IF_PTR ipif, /* [IN] the interface descriptor */
MC_MEMBER_PTR _PTR_ pmember /* [IN] the group to leave */
)
{ /* Body */
uint_32 status, tmp;
/* leave the group on the physical interface */
status = IGMP_filter_rm(ipif, (*pmember)->IGRP.imr_multiaddr.s_addr);
/* leave the group */
tmp = IGMP_member_delete(pmember);
if (tmp != RTCS_OK && status == RTCS_OK) {
status = tmp;
} /* Endif */
return status;
} /* Endbody */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : IGMP_ipif_add
* Returned Values : error code
* Comments :
* init the IGMP part of a given interface. called by IPIF_add
*
*END*-----------------------------------------------------------------*/
uint_32 IGMP_ipif_add
(
IP_IF_PTR ipif /* [IN] the interface descriptor */
)
{ /* Body */
ipif->IGMP_MEMBER = NULL;
ipif->IGMP_UNBIND = IGMP_ipif_unbind_nosock;
#ifdef IGMP_V2
ipif->IGMP_V1_ROUTER_FLAG = FALSE;
#endif
return RTCS_OK;
} /* Endbody */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : IGMP_ipif_bind
* Returned Values : error code
* Comments :
* bind the IGMP part of a given interface. called by IPIF_bind
* mainly for joining the ALL_HOSTS group.
*
*END*-----------------------------------------------------------------*/
uint_32 IGMP_ipif_bind
(
IP_IF_PTR ipif, /* [IN] the interface descriptor */
_ip_address ip_address /* [IN] the ip address of the interface */
)
{ /* Body */
ip_mreq group;
/* join the ALL_HOSTS group */
group.imr_multiaddr.s_addr = INADDR_ALLHOSTS_GROUP;
group.imr_interface.s_addr = ip_address;
return IGMP_join_if_local(ipif, &group);
} /* Endbody */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : IGMP_ipif_unbind_nosock
* Returned Values : error code
* Comments :
* unbind a address to an interface. called by IPIF_unbind.
* leave the groups still joined on this address/interface.
*
*END*-----------------------------------------------------------------*/
uint_32 IGMP_ipif_unbind_nosock
(
IP_IF_PTR ipif, /* [IN] the interface descriptor */
_ip_address ip_address /* [IN] the ip address of the interface */
)
{ /* Body */
MC_MEMBER_PTR _PTR_ pmember;
uint_32 status, tmp;
status = RTCS_OK;
/* leave all joined groups */
for (pmember = &ipif->IGMP_MEMBER; *pmember;) {
if ((*pmember)->IGRP.imr_interface.s_addr != ip_address) {
pmember = &(*pmember)->NEXT;
continue;
} /* Endif */
tmp = IGMP_leave_if_local(ipif, pmember);
if (tmp != RTCS_OK && status == RTCS_OK) {
status = tmp;
} /* Endif */
} /* Endfor */
return status;
} /* Endbody */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : IGMP_is_member
* Returned Values : boolean
* Comments :
* return TRUE if the socket is a member of a given group.
*
*END*-----------------------------------------------------------------*/
struct IGMP_is_member_test_struct {
_ip_address multiaddr;
IP_IF_PTR ipif;
MC_MEMBER_PTR _PTR_ phead;
boolean result;
};
static boolean IGMP_is_member_test
(
_ip_address node_ip,
_ip_address node_mask,
pointer node_data,
pointer data
)
{ /* Body */
struct IGMP_is_member_test_struct _PTR_ testdata = data;
IP_ROUTE_PTR route = node_data;
IP_ROUTE_DIRECT_PTR search_ptr;
ip_mreq group;
if (route && route->DIRECT) {
search_ptr = route->DIRECT;
group.imr_multiaddr.s_addr = testdata->multiaddr;
do { /* Body */
if (search_ptr->NETIF == testdata->ipif) {
group.imr_interface.s_addr = search_ptr->ADDRESS;
if (IGMP_member_find(testdata->phead, &group)) {
testdata->result = TRUE;
return TRUE;
} /* Endif */
} /* Endif */
search_ptr = search_ptr->NEXT;
} while(search_ptr != route->DIRECT);
} /* Endif */
return FALSE;
} /* Body */
boolean IGMP_is_member
(
MC_MEMBER_PTR _PTR_ phead, /* [IN] head of MCB list */
IP_IF_PTR ipif, /* [IN] the incoming interface */
_ip_address multiaddr /* [IN] the multicast ip */
)
{ /* Body */
IP_CFG_STRUCT_PTR IP_cfg_ptr = RTCS_getcfg(IP);
struct IGMP_is_member_test_struct testdata;
if (!*phead) {
return FALSE;
} /* Endif */
testdata.multiaddr = multiaddr;
testdata.ipif = ipif;
testdata.phead = phead;
testdata.result = FALSE;
/*
** Scan all directly connected networks, to have all the ip
** address of this interface
*/
IPRADIX_walk(&IP_cfg_ptr->ROUTE_ROOT.NODE, IGMP_is_member_test, &testdata);
return testdata.result;
} /* Endbody */
#endif
/* EOF */