2 * IGMP Snooping Layer: IGMP Snooping module runs at layer 2. IGMP
3 * Snooping layer uses the multicast information in the IGMP messages
4 * exchanged between the participating hosts and multicast routers to
5 * update the multicast forwarding database. This file contains the
6 * common code routines of IGS module.
8 * Copyright (C) 2010, Broadcom Corporation
11 * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom Corporation;
12 * the contents of this file may not be disclosed to third parties, copied
13 * or duplicated in any form, in whole or in part, without the prior
14 * written permission of Broadcom Corporation.
16 * $Id: igsc.c 247842 2011-03-22 02:10:23Z jihuac $
21 #include <bcmendian.h>
22 #include <proto/bcmip.h>
27 #include <osl_linux.h>
28 #else /* defined(osl_xx) */
29 #error "Unsupported osl"
30 #endif /* defined(osl_xx) */
32 #include "emfc_export.h"
33 #include "igs_export.h"
34 #include "igsc_export.h"
38 static mc_grp_spl_t mc_addr_rsvd
[] =
40 { 0xe0000001, 0xffffffff }, /* All hosts */
41 { 0xe0000002, 0xffffffff }, /* All routers */
42 { 0xe0000004, 0xffffffff }, /* DVMRP routers */
43 { 0xe0000005, 0xffffffff }, /* OSPF1 routers */
44 { 0xe0000006, 0xffffffff }, /* OSPF2 routers */
45 { 0xe0000009, 0xffffffff }, /* RIP v2 routers */
46 { 0xe000000d, 0xffffffff }, /* PIMd routers */
47 { 0xe0000010, 0xffffffff }, /* IGMP v3 routers */
48 { 0xe00000fb, 0xffffffff }, /* Reserved */
49 { 0xe000ff87, 0xffffffff }, /* Reserved */
50 { 0xeffffffa, 0xffffffff }, /* UPnP */
54 igsc_is_reserved(uint32 addr
)
58 for (i
= 0; i
< sizeof(mc_addr_rsvd
)/sizeof(mc_grp_spl_t
); i
++)
60 if ((addr
& mc_addr_rsvd
[i
].mask
) ==
61 (mc_addr_rsvd
[i
].addr
& mc_addr_rsvd
[i
].mask
))
71 * Description: This function is called if the snooper doesn't receive
72 * membership query from a router for timeout interval.
73 * It deletes the router port entry from the list. If this
74 * is the last router on the interface then the EMF router
75 * port entry is also deleted.
77 * Input: rtlist_ptr - Multicast router interface/port entry
80 igsc_rtlist_timer(igsc_rtlist_t
*rtlist_ptr
)
83 igsc_rtlist_t
*rtl_ptr
;
84 bool mr_port_found
= FALSE
;
85 igsc_info_t
*igsc_info
;
87 igsc_info
= rtlist_ptr
->igsc_info
;
89 /* Delete the expired router port entry */
90 clist_delete(&rtlist_ptr
->list
);
92 /* Check if there are more routers on this port/interface */
93 for (ptr
= igsc_info
->rtlist_head
.next
;
94 ptr
!= &igsc_info
->rtlist_head
; ptr
= ptr
->next
)
96 rtl_ptr
= clist_entry(ptr
, igsc_rtlist_t
, list
);
97 if (rtl_ptr
->ifp
== rtlist_ptr
->ifp
)
104 /* Last multicast router on this port/interface */
107 IGS_DEBUG("Delete the router port %p in the EMF\n",
109 emfc_rtport_del(igsc_info
->emf_handle
, rtlist_ptr
->ifp
);
112 MFREE(igsc_info
->osh
, rtlist_ptr
, sizeof(igsc_rtlist_t
));
118 * Description: This function is called to find the entry in the router
119 * port list given the IP Address and the interface pointer.
121 * Input: igsc_info - IGSC Global Instance handle
122 * ifp - Interface pointer
123 * mr_ip - IP address of the router
125 * Return: Pointer to the entry found or NULL otherwise
127 static igsc_rtlist_t
*
128 igsc_rtlist_find(igsc_info_t
*igsc_info
, void *ifp
, uint32 mr_ip
)
131 igsc_rtlist_t
*rtl_ptr
;
133 OSL_LOCK(igsc_info
->rtlist_lock
);
135 for (ptr
= igsc_info
->rtlist_head
.next
;
136 ptr
!= &igsc_info
->rtlist_head
; ptr
= ptr
->next
)
138 rtl_ptr
= clist_entry(ptr
, igsc_rtlist_t
, list
);
140 if ((rtl_ptr
->ifp
== ifp
) && (rtl_ptr
->mr_ip
== mr_ip
))
142 OSL_UNLOCK(igsc_info
->rtlist_lock
);
143 IGS_DEBUG("Router port entry %x %p found\n",
149 OSL_UNLOCK(igsc_info
->rtlist_lock
);
155 * Description: This function is called when the snooper receives IGMP
156 * membership query on one of the ports. It adds an entry
157 * to the multicast router port list. Each entry of the
158 * list contains the IP address of the multicast router
159 * and the interface/port on which it is present. It calls
160 * the EMF function to add a router port entry to the list
163 * Input: igsc_info - IGSC Global Instance handle
164 * ifp - Interface pointer
165 * mr_ip - IP address of the router
167 * Return: SUCCESS/FAILURE
170 igsc_rtlist_add(igsc_info_t
*igsc_info
, void *ifp
, uint32 mr_ip
)
172 igsc_rtlist_t
*rtlist_ptr
;
174 /* If the router port list entry exists already then refresh the
175 * timer for this entry.
177 if ((rtlist_ptr
= igsc_rtlist_find(igsc_info
, ifp
, mr_ip
)) != NULL
)
179 osl_timer_update(rtlist_ptr
->rtlist_timer
, igsc_info
->query_intv
,
181 IGS_DEBUG("Duplicate router port entry %x %p\n", mr_ip
, ifp
);
185 /* Allocate and intialize the entry */
186 rtlist_ptr
= MALLOC(igsc_info
->osh
, sizeof(igsc_rtlist_t
));
187 if (rtlist_ptr
== NULL
)
189 IGS_ERROR("Failed to allocate memory size %d for rtport list\n",
190 sizeof(igsc_rtlist_t
));
194 rtlist_ptr
->ifp
= ifp
;
195 rtlist_ptr
->mr_ip
= mr_ip
;
196 rtlist_ptr
->igsc_info
= igsc_info
;
198 OSL_LOCK(igsc_info
->rtlist_lock
);
200 /* Add the entry to the EMF router port list */
201 if (emfc_rtport_add(igsc_info
->emf_handle
, ifp
) != SUCCESS
)
203 OSL_UNLOCK(igsc_info
->rtlist_lock
);
204 MFREE(igsc_info
->osh
, rtlist_ptr
, sizeof(igsc_rtlist_t
));
205 IGS_ERROR("Failed to add EMF rtport entry for %p\n", ifp
);
209 /* Add timer to delete the entry on igmp query timeout */
210 rtlist_ptr
->rtlist_timer
= osl_timer_init("MR_PORT_LIST_TIMER",
211 (void (*)(void *))igsc_rtlist_timer
,
214 if (rtlist_ptr
->rtlist_timer
== NULL
)
216 OSL_UNLOCK(igsc_info
->rtlist_lock
);
217 emfc_rtport_del(igsc_info
->emf_handle
, ifp
);
218 MFREE(igsc_info
->osh
, rtlist_ptr
, sizeof(igsc_rtlist_t
));
219 IGS_ERROR("Failed to allocate memory size %d for timer\n",
220 sizeof(osl_timer_t
));
224 osl_timer_add(rtlist_ptr
->rtlist_timer
, igsc_info
->query_intv
, FALSE
);
226 /* Add the entry to IGS router port list */
227 clist_add_head(&igsc_info
->rtlist_head
, &rtlist_ptr
->list
);
229 OSL_UNLOCK(igsc_info
->rtlist_lock
);
235 * Description: This function is called to clear the IGSC router port list.
236 * It also call the API to delete the corresponding EMF router
239 * Input: igsc_info - IGSC Global Instance handle
242 igsc_rtlist_clear(igsc_info_t
*igsc_info
)
245 igsc_rtlist_t
*rtl_ptr
;
247 OSL_LOCK(igsc_info
->rtlist_lock
);
249 for (ptr
= igsc_info
->rtlist_head
.next
;
250 ptr
!= &igsc_info
->rtlist_head
; ptr
= ptr
->next
)
252 rtl_ptr
= clist_entry(ptr
, igsc_rtlist_t
, list
);
253 osl_timer_del(rtl_ptr
->rtlist_timer
);
254 emfc_rtport_del(igsc_info
->emf_handle
, rtl_ptr
->ifp
);
256 MFREE(igsc_info
->osh
, rtl_ptr
, sizeof(igsc_rtlist_t
));
259 OSL_UNLOCK(igsc_info
->rtlist_lock
);
264 #ifdef SUPPORT_IGMP_V3
265 /* Add Joining Member or Update joined member */
266 static int32
igsc_update_join_member(igsc_info_t
*igsc_info
, void *ifp
, uint32 dest_ip
, uint32 mcast_ip
, uint32 mh_ip
)
270 if (igsc_is_reserved(dest_ip
)) {
271 IGSC_STATS_INCR(igsc_info
, igmp_not_handled
);
272 IGS_DEBUG("Reserved multicast address %x frame\n",
274 return ((ret
== SUCCESS
) ? EMF_FORWARD
: EMF_FLOOD
);
276 /* When a host membership report is received add/refresh the entry for the host. */
277 IGS_DEBUG("Join mcast_addr=%x\n", mcast_ip
);
278 IGSC_STATS_INCR(igsc_info
, igmp_v2reports
);
280 /* SUPPORT_IGMP_V3 Added */
281 if ( (ret
= igsc_sdb_member_add(igsc_info
, ifp
, IPV4_MCADDR_ALLHOSTS
, mh_ip
)) == SUCCESS
)
282 ret
= igsc_sdb_member_add(igsc_info
, ifp
, mcast_ip
, mh_ip
);
283 return ((ret
== SUCCESS
) ? EMF_FORWARD
: EMF_FLOOD
);
286 /* Remove leave members*/
287 static int32
igsc_update_leave_member(igsc_info_t
*igsc_info
, void *ifp
, uint32 mcast_ip
, uint32 mh_ip
)
292 IGSC_STATS_INCR(igsc_info
, igmp_leaves
);
293 IGS_DEBUG("Leave mcast_addr=%x\n", mcast_ip
);
295 /* SUPPORT_IGMP_V3 Added */
296 if ( (ret
= igsc_sdb_member_del(igsc_info
, ifp
, IPV4_MCADDR_ALLHOSTS
, mh_ip
))==SUCCESS
)
297 ret
= igsc_sdb_member_del(igsc_info
, ifp
, mcast_ip
, mh_ip
);
300 IGS_WARN("Deleting unknown member with grp %x host %x if %p",
301 igmpv3g
->mcast_addr
, mh_ip
, ifp
);
302 return ((ret
== SUCCESS
) ? EMF_FORWARD
: EMF_FLOOD
);
309 * Description: This function is called by EMFL when an IGMP frame
310 * is received. Based on the IGMP packet type it either
311 * adds, deletes or refreshes the MFDB entry.
313 * Input: s - Snooper global instance data cookie
314 * ifp - Pointer to interface the frame arrived on.
315 * iph - Points to start of IP header in the packet.
316 * igmph - Points to start of IGMP header in the packet.
317 * from_rp - TRUE when received from router port.
319 * Return: EMF_FLOOD - Flood the frame.
320 * EMF_SENDUP - Deliver the packet to IP layer.
323 igsc_input(emfc_snooper_t
*s
, void *ifp
, uint8
*iph
, uint8
*igmph
, bool from_rp
)
326 igsc_info_t
*igsc_info
;
327 uint32 mgrp_ip
, mh_ip
, dest_ip
;
328 #ifdef SUPPORT_IGMP_V3
329 uint16 grp_num
=0, offset
;
330 igmpv3_report_t
*igmpv3h
;
331 igmpv3_group_t
*igmpv3g
;
336 igsc_info
= IGSC_INFO(s
);
338 IGSC_STATS_INCR(igsc_info
, igmp_packets
);
342 IGS_DEBUG("Ignoring IGMP frame from router port\n");
343 IGSC_STATS_INCR(igsc_info
, igmp_not_handled
);
344 #ifdef SUPPORT_IGMP_V3
345 /* Convert Query to Unicast */
346 if (igmph
[IGMPV2_TYPE_OFFSET
]==IGMPV2_HOST_MEMBERSHIP_QUERY
){
347 return (EMF_CONVERT_QUERY
);
354 mgrp_ip
= ntoh32(*((uint32
*)(igmph
+ IGMPV2_GRP_ADDR_OFFSET
)));
355 mh_ip
= ntoh32(*((uint32
*)(iph
+ IPV4_SRC_IP_OFFSET
)));
356 #ifdef SUPPORT_IGMP_V3
357 dest_ip
= ntoh32(*((uint32
*)(iph
+ IPV4_DEST_IP_OFFSET
)));
360 switch (igmph
[IGMPV2_TYPE_OFFSET
])
362 case IGMPV2_HOST_NEW_MEMBERSHIP_REPORT
:
363 #ifdef SUPPORT_IGMP_V3
364 /* Move report to function igsc_update_join_member() */
365 ret
= igsc_update_join_member(igsc_info
, ifp
, dest_ip
, mgrp_ip
, mh_ip
);
368 /* Ignore frames received with reserved addresses */
369 dest_ip
= ntoh32(*((uint32
*)(iph
+ IPV4_DEST_IP_OFFSET
)));
370 if (igsc_is_reserved(dest_ip
))
372 IGSC_STATS_INCR(igsc_info
, igmp_not_handled
);
373 IGS_DEBUG("Reserved multicast address %x frame\n",
378 /* When a host membership report is received add/refresh the
379 * entry for the host.
381 IGSC_STATS_INCR(igsc_info
, igmp_v2reports
);
382 ret
= igsc_sdb_member_add(igsc_info
, ifp
, mgrp_ip
, mh_ip
);
384 return ((ret
== SUCCESS
) ? EMF_FORWARD
: EMF_FLOOD
);
386 case IGMPV2_LEAVE_GROUP_MESSAGE
:
387 #ifdef SUPPORT_IGMP_V3
388 ret
= igsc_update_leave_member(igsc_info
, ifp
, mgrp_ip
, mh_ip
);
389 /* Move Leave to function igsc_update_leave_member() */
392 /* Remove group entry for the host when a leave message is
395 IGSC_STATS_INCR(igsc_info
, igmp_leaves
);
396 ret
= igsc_sdb_member_del(igsc_info
, ifp
, mgrp_ip
, mh_ip
);
399 IGS_WARN("Deleting unknown member with grp %x host %x if %p",
400 mgrp_ip
, mh_ip
, ifp
);
404 case IGMPV2_HOST_MEMBERSHIP_REPORT
:
405 IGSC_STATS_INCR(igsc_info
, igmp_reports
);
408 case IGMPV2_HOST_MEMBERSHIP_QUERY
:
409 IGSC_STATS_INCR(igsc_info
, igmp_queries
);
411 /* Update the multicast router port list */
414 IGS_DEBUG("Updating router port list with %x %p\n",
416 igsc_rtlist_add(igsc_info
, ifp
, mh_ip
);
419 #ifdef SUPPORT_IGMP_V3
420 case IGMPV3_HOST_MEMBERSHIP_REPORT
:
421 igmpv3h
= (igmpv3_report_t
*)igmph
;
422 igmpv3g
=(igmpv3_group_t
*)(igmpv3h
+1);
424 for ( grp_num
=0; grp_num
<igmpv3h
->group_num
; grp_num
++ ) {
426 switch (igmpv3g
->type
) {
427 case IGMPV3_MODE_IS_EXCLUDE
:
428 case IGMPV3_ALLOW_NEW_SOURCES
:
429 case IGMPV3_BLOCK_OLD_SOURCES
:
430 case IGMPV3_CHANGE_TO_EXCLUDE
:
432 IGS_DEBUG("Join mcast_addr=%x\n",
433 igmpv3g
->mcast_addr
);
434 ret
= igsc_update_join_member(igsc_info
, ifp
,
435 dest_ip
, igmpv3g
->mcast_addr
, mh_ip
);
437 case IGMPV3_CHANGE_TO_INCLUDE
:
438 case IGMPV3_MODE_IS_INCLUDE
:
440 IGS_DEBUG("Leave mcast_addr=%x, src_num=%x\n",
441 igmpv3g
->mcast_addr
, igmpv3g
->src_num
);
442 if ( igmpv3g
->src_num
== 0 )
443 ret
= igsc_update_leave_member(igsc_info
, ifp
,
444 igmpv3g
->mcast_addr
, mh_ip
);
446 ret
= igsc_update_join_member(igsc_info
, ifp
,
447 dest_ip
, igmpv3g
->mcast_addr
, mh_ip
);
452 offset
=sizeof(igmpv3_group_t
)+igmpv3g
->src_num
*IGMPV3_SRC_ADDR_LEN
+igmpv3g
->aux_len
;
453 igmpv3g
=(igmpv3_group_t
*)(((unsigned char *)igmpv3g
)+offset
);
459 IGS_WARN("IGMP type %d not handled\n", igmph
[IGMPV2_TYPE_OFFSET
]);
460 IGSC_STATS_INCR(igsc_info
, igmp_not_handled
);
468 * Internet checksum routine
471 inet_cksum(uint8
*buf
, int32 len
)
491 sum
= (sum
& 0xffff) + (sum
>> 16);
494 return (hton16(~sum
));
498 * Description: This function adds the IP header, IGMP header and data.
501 igsc_igmp_pkt_encap(uint8
*ip
, uint32 src_ip
, uint32 dest_ip
,
502 uint8 igmp_type
, uint8 max_rsp
, uint32 grp_addr
)
506 /* Prepare the IP header */
507 ip
[IP_VER_OFFSET
] = ((IP_VER_4
<< 4) | (IPV4_MIN_HLEN
>> 2));
508 ip
[IPV4_TOS_OFFSET
] = 0xc0;
509 *((uint16
*)(ip
+ IPV4_LEN_OFFSET
)) = hton16(IPV4_MIN_HLEN
+ IGMP_HLEN
);
510 *((uint16
*)(ip
+ IPV4_ID_OFFSET
)) = 0;
511 *((uint16
*)(ip
+ IPV4_FRAG_OFFSET
)) = 0;
512 ip
[IPV4_TTL_OFFSET
] = 1;
513 ip
[IPV4_PROT_OFFSET
] = IP_PROT_IGMP
;
514 *((uint16
*)(ip
+ IPV4_CHKSUM_OFFSET
)) = 0;
515 *((uint32
*)(ip
+ IPV4_SRC_IP_OFFSET
)) = src_ip
;
516 *((uint32
*)(ip
+ IPV4_DEST_IP_OFFSET
)) = dest_ip
;
517 *((uint16
*)(ip
+ IPV4_CHKSUM_OFFSET
)) = inet_cksum(ip
, IPV4_MIN_HLEN
);
519 /* Fill the IGMP header fields */
520 igmp
= ip
+ IPV4_MIN_HLEN
;
521 igmp
[IGMPV2_TYPE_OFFSET
] = igmp_type
;
522 igmp
[IGMPV2_MAXRSP_TIME_OFFSET
] = max_rsp
;
523 *((uint16
*)(igmp
+ IGMPV2_CHECKSUM_OFFSET
)) = 0;
524 *((uint32
*)(igmp
+ IGMPV2_GRP_ADDR_OFFSET
)) = grp_addr
;
525 *((uint16
*)(igmp
+ IGMPV2_CHECKSUM_OFFSET
)) = inet_cksum(ip
,
526 IGMP_HLEN
+ IPV4_MIN_HLEN
);
532 * Description: This functions generates an IGMP Query. It is used to
533 * quickly determine the group members on the attached bridge
536 * Return: SUCCESS or FAILURE
539 igsc_igmp_query_send(igsc_info_t
*igsc_info
)
544 /* Build the IGMP Query packet */
545 igsc_igmp_pkt_encap((uint8
*)ip
, lan_ip
, hton32(IPV4_MCADDR_ALLHOSTS
),
546 IGMPV2_HOST_MEMBERSHIP_QUERY
, IGMPV2_MAXRSP_TIME
/ 100, 0);
548 IGS_DEBUG("Forwarding IGMP Query on to bridge ports\n");
550 return (igsc_info
->wrapper
.igs_broadcast(igsc_info
->igs_info
, (uint8
*)ip
,
551 IGMP_HLEN
+ IPV4_MIN_HLEN
,
552 IPV4_MCADDR_ALLHOSTS
));
556 * Description: This function is called by the EMFL when forwarding
559 * Input: snooper - Snooper gloabl instance data.
561 * Return: SUCCESS or FAILURE
564 igsc_emf_enabled(emfc_snooper_t
*snooper
)
566 IGS_INFO("EMF enable callback called\n");
568 /* Send an IGMP Query packet to quickly learn the members present
571 if (igsc_igmp_query_send(IGSC_INFO(snooper
)) != SUCCESS
)
573 IGS_ERROR("IGMP Query send failed\n");
581 * Description: This function is called by the EMFL when forwarding
584 * Input: snooper - Snooper gloabl instance data.
586 * Return: SUCCESS or FAILURE
589 igsc_emf_disabled(emfc_snooper_t
*snooper
)
591 IGS_INFO("EMF disable callback\n");
592 igsc_sdb_clear(IGSC_INFO(snooper
));
593 igsc_rtlist_clear(IGSC_INFO(snooper
));
598 * IGSL Packet Counters/Statistics Function
601 igsc_stats_get(igsc_info_t
*igsc_info
, igs_stats_t
*stats
, uint32 size
)
603 if (igsc_info
== NULL
)
605 IGS_ERROR("Invalid IGSC handle passed\n");
611 IGS_ERROR("Invalid buffer input\n");
615 if (size
< sizeof(igs_stats_t
))
617 IGS_ERROR("Insufficient buffer size %d\n", size
);
621 *stats
= igsc_info
->stats
;
627 * RTPORT Interface Listing
630 igsc_rtport_list(igsc_info_t
*igsc
, igs_cfg_rtport_list_t
*list
, uint32 size
)
632 int32 index
= 0, bytes
= 0;
634 igsc_rtlist_t
*rtl_ptr
;
636 for (ptr
= igsc
->rtlist_head
.next
; ptr
!= &igsc
->rtlist_head
; ptr
= ptr
->next
)
638 rtl_ptr
= clist_entry(ptr
, igsc_rtlist_t
, list
);
640 bytes
+= sizeof(igs_cfg_rtport_list_t
);
644 list
->rtport_entry
[index
].mr_ip
= rtl_ptr
->mr_ip
;
645 strncpy(list
->rtport_entry
[index
].if_name
, DEV_IFNAME(rtl_ptr
->ifp
), 16);
649 /* Update the total number of entries */
650 list
->num_entries
= index
;
656 igsc_cfg_request_process(igsc_info_t
*igsc_info
, igs_cfg_request_t
*cfg
)
658 IGS_DEBUG("IGS command identifier: %d\n", cfg
->command_id
);
660 switch (cfg
->command_id
)
662 case IGSCFG_CMD_IGS_STATS
:
663 if (igsc_stats_get(igsc_info
, (igs_stats_t
*)cfg
->arg
,
664 cfg
->size
) != SUCCESS
)
666 cfg
->status
= IGSCFG_STATUS_FAILURE
;
667 cfg
->size
= sprintf(cfg
->arg
, "IGS stats get failed\n");
670 cfg
->status
= IGSCFG_STATUS_SUCCESS
;
673 case IGSCFG_CMD_IGSDB_LIST
:
674 if (igsc_sdb_list(igsc_info
, (igs_cfg_sdb_list_t
*)cfg
->arg
,
675 cfg
->size
) != SUCCESS
)
677 cfg
->status
= IGSCFG_STATUS_FAILURE
;
678 cfg
->size
= sprintf(cfg
->arg
, "IGSDB listing failed\n");
681 cfg
->status
= IGSCFG_STATUS_SUCCESS
;
684 case IGSCFG_CMD_RTPORT_LIST
:
685 if (igsc_rtport_list(igsc_info
, (igs_cfg_rtport_list_t
*)cfg
->arg
,
686 cfg
->size
) != SUCCESS
)
688 cfg
->status
= EMFCFG_STATUS_FAILURE
;
689 cfg
->size
= sprintf(cfg
->arg
, "RTPORT list get failed\n");
692 cfg
->status
= EMFCFG_STATUS_SUCCESS
;
696 cfg
->status
= IGSCFG_STATUS_CMD_UNKNOWN
;
697 cfg
->size
= sprintf(cfg
->arg
, "Unknown command id %d\n",
704 * Description: This function is called from the OS specific module
705 * init routine to initialize the IGSL. This function
706 * primarily initializes the IGSL global data and IGSDB.
708 * Input: inst_id - IGS instance identifier.
709 * igs_info - IGSL OS Specific global data handle
710 * osh - OS abstraction layer handle
711 * wrapper - wrapper specific info
713 * Return: igsc_info - IGSL Common code global data handle
716 igsc_init(int8
*inst_id
, void *igs_info
, osl_t
*osh
, igsc_wrapper_t
*wrapper
)
718 igsc_info_t
*igsc_info
;
722 IGS_ERROR("Instance identifier NULL\n");
728 IGS_ERROR("wrapper info NULL\n");
732 IGS_DEBUG("Initializing IGMP Snooping Layer\n");
734 /* Allocate memory */
735 igsc_info
= MALLOC(osh
, sizeof(igsc_info_t
));
736 if (igsc_info
== NULL
)
738 IGS_ERROR("Failed to allocated memory size %d for MFL\n",
739 sizeof(igsc_info_t
));
743 IGS_DEBUG("Allocated memory for IGSC info\n");
745 /* Initialize the IGS global data */
746 bzero(igsc_info
, sizeof(igsc_info_t
));
747 igsc_info
->osh
= osh
;
748 igsc_info
->igs_info
= igs_info
;
749 igsc_info
->grp_mem_intv
= IGMPV2_GRP_MEM_INTV
;
750 igsc_info
->query_intv
= IGMPV2_QUERY_INTV
;
752 /* Fill in the wrapper specific data */
753 igsc_info
->wrapper
.igs_broadcast
= wrapper
->igs_broadcast
;
755 /* Initialize the IGSDB */
756 igsc_sdb_init(igsc_info
);
758 igsc_info
->sdb_lock
= OSL_LOCK_CREATE("SDB Lock");
760 if (igsc_info
->sdb_lock
== NULL
)
762 igsc_sdb_clear(igsc_info
);
763 MFREE(osh
, igsc_info
, sizeof(igsc_info_t
));
767 /* Register IGMP v2 Snooper with EMFL */
768 igsc_info
->snooper
.input_fn
= igsc_input
;
769 igsc_info
->snooper
.emf_enable_fn
= igsc_emf_enabled
;
770 igsc_info
->snooper
.emf_disable_fn
= igsc_emf_disabled
;
772 if (emfc_igmp_snooper_register(inst_id
, &igsc_info
->emf_handle
,
773 &igsc_info
->snooper
) != SUCCESS
)
775 IGS_ERROR("IGMP Snooper couldn't register with EMF\n");
776 igsc_sdb_clear(igsc_info
);
777 OSL_LOCK_DESTROY(igsc_info
->sdb_lock
);
778 MFREE(osh
, igsc_info
, sizeof(igsc_info_t
));
782 /* Initialize router port list head */
783 clist_init_head(&igsc_info
->rtlist_head
);
785 igsc_info
->rtlist_lock
= OSL_LOCK_CREATE("Router List Lock");
787 if (igsc_info
->rtlist_lock
== NULL
)
789 emfc_igmp_snooper_unregister(igsc_info
->emf_handle
);
790 igsc_sdb_clear(igsc_info
);
791 OSL_LOCK_DESTROY(igsc_info
->sdb_lock
);
792 MFREE(osh
, igsc_info
, sizeof(igsc_info_t
));
796 IGS_DEBUG("Initialized IGSDB\n");
802 * Description: This function is called from OS specific module cleanup
803 * routine. This routine primarily stops the group interval
804 * timers and cleans up the IGSDB entries.
807 igsc_exit(igsc_info_t
*igsc_info
)
809 emfc_igmp_snooper_unregister(igsc_info
->emf_handle
);
811 /* Cleanup the IGS router port list entries */
812 igsc_rtlist_clear(igsc_info
);
813 OSL_LOCK_DESTROY(igsc_info
->rtlist_lock
);
815 /* Cleanup the IGSDB */
816 igsc_sdb_clear(igsc_info
);
817 OSL_LOCK_DESTROY(igsc_info
->sdb_lock
);
819 MFREE(igsc_info
->osh
, igsc_info
, sizeof(igsc_info_t
));
821 IGS_DEBUG("Cleaned up IGSL, exiting common code\n");
828 * Description: This function is called to delete the IGSDB
829 * rtport entries on an interface
831 * Input: igsc_info - igsc info pointer
832 * ifp - interface pointer
834 * Return: SUCCESS or FAILURE
837 igsc_interface_rtport_del(igsc_info_t
*igsc_info
, void *ifp
)
839 clist_head_t
*ptr
, *tmp
;
840 igsc_rtlist_t
*rtl_ptr
;
842 OSL_LOCK(igsc_info
->rtlist_lock
);
844 for (ptr
= igsc_info
->rtlist_head
.next
;
845 ptr
!= &igsc_info
->rtlist_head
; ptr
= tmp
)
847 rtl_ptr
= clist_entry(ptr
, igsc_rtlist_t
, list
);
850 if (rtl_ptr
->ifp
== (igsc_rtlist_t
*)ifp
)
852 IGS_DEBUG("Router port entry %p found\n");
853 emfc_rtport_del(igsc_info
->emf_handle
, rtl_ptr
->ifp
);
855 MFREE(igsc_info
->osh
, rtl_ptr
, sizeof(igsc_rtlist_t
));
859 OSL_UNLOCK(igsc_info
->rtlist_lock
);