2 * Efficient Multicast Forwarding Layer: This module does the efficient
3 * layer 2 forwarding of multicast streams, i.e., forward the streams
4 * only on to the ports that have corresponding group members there by
5 * reducing the bandwidth utilization and latency. It uses the information
6 * updated by IGMP Snooping layer to do the optimal forwarding. This file
7 * contains the common code routines of EMFL.
9 * Copyright (C) 2010, Broadcom Corporation
10 * All Rights Reserved.
12 * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom Corporation;
13 * the contents of this file may not be disclosed to third parties, copied
14 * or duplicated in any form, in whole or in part, without the prior
15 * written permission of Broadcom Corporation.
17 * $Id: emfc.c 241182 2011-02-17 21:50:03Z gmo $
21 #include <bcmendian.h>
22 #include <proto/ethernet.h>
23 #include <proto/bcmip.h>
26 #include <osl_linux.h>
27 #else /* defined(osl_xx) */
28 #error "Unsupported osl"
29 #endif /* defined(osl_xx) */
33 #include "emfc_export.h"
35 #include "emf_export.h"
37 /* BH-enabled helpers */
38 #define EMF_RELOCK(lock) do { \
40 spin_lock(&((lock)->slock)); \
42 #define OSL_RELOCK(lock) do { \
43 spin_unlock(&((lock)->slock)); \
47 static CLIST_DECL_INIT(emfc_list_head
);
48 static osl_lock_t emfc_list_lock
;
51 emfc_instance_find(char *inst_id
)
58 EMF_ERROR("Invalid instance id string\n");
62 OSL_LOCK(emfc_list_lock
);
64 for (ptr
= emfc_list_head
.next
; ptr
!= &emfc_list_head
;
67 emfc
= clist_entry(ptr
, emfc_info_t
, emfc_list
);
69 if (strcmp(inst_id
, emfc
->inst_id
) == 0)
71 OSL_UNLOCK(emfc_list_lock
);
76 OSL_UNLOCK(emfc_list_lock
);
82 * Description: This function is called by the IGMP snooper layer to
83 * register snooper instance with EMFL.
85 * Input: inst_id - Instance identier used to associate EMF
86 * and IGMP snooper instances.
87 * emfc - EMFL Common code global instance handle
88 * snooper - Contains snooper specific parameters and
89 * event callback functions. These functions
90 * are called by EMFL on events like IGMP
91 * packet receive, EMF enable and disable.
92 * The snooper parameter needs to global or
95 * Return: SUCCESS or FAILURE
98 emfc_igmp_snooper_register(int8
*inst_id
, emfc_info_t
**emfc
, emfc_snooper_t
*snooper
)
103 EMF_ERROR("Snooper parameter should be non NULL\n");
109 EMF_ERROR("EMF handle should be non NULL\n");
113 /* Validate the instance id */
114 if ((*emfc
= emfc_instance_find(inst_id
)) == NULL
)
116 EMF_ERROR("EMF Instance doesn't exist\n");
120 if (snooper
->input_fn
== NULL
)
122 EMF_ERROR("Snooper input function should be non NULL\n");
126 (*emfc
)->snooper
= snooper
;
132 * Description: This function is called by the IGMP snooper layer
133 * to unregister snooper instance.
135 * Input: handle - Handle returned during registration.
136 * snooper - Contains snooper specific parameters and
139 emfc_igmp_snooper_unregister(emfc_info_t
*emfc
)
143 EMF_ERROR("Unregistering using invalid handle\n");
147 emfc
->snooper
= NULL
;
153 * Description: This function handles the unregistered frame forwarding.
154 * IGMP frames are forwarded on router ports. Data frames
155 * are flooded on to user configured UFFP.
157 * Input: emfc - EMFC Global instance data
158 * sdu - Pointer to packet buffer.
159 * ifp - Interface on which the packet arrived.
160 * dest_ip - Multicast destination IP address
161 * rt_port - TRUE when the packet is received from IP
162 * Stack otherwise FALSE.
164 * Return: EMF_TAKEN - EMF has taken the ownership of the packet.
165 * EMF_NOP - No processing needed by EMF, just return
167 * EMF_DROP - Drop and free the packet.
170 emfc_unreg_frame_handle(emfc_info_t
*emfc
, void *sdu
, void *ifp
, uint8 proto
,
171 uint32 dest_ip
, bool rt_port
)
175 uint32 mcast_flooded
= 0;
177 /* Forward the frame on to router port */
180 EMF_DEBUG("Sending frame on to router port\n");
182 if ((sdu_clone
= PKTDUP(emfc
->osh
, sdu
)) == NULL
)
184 EMFC_PROT_STATS_INCR(emfc
, proto
, igmp_frames_dropped
,
189 emfc
->wrapper
.sendup_fn(emfc
->emfi
, sdu_clone
);
191 EMFC_PROT_STATS_INCR(emfc
, proto
, igmp_frames_sentup
,
195 OSL_LOCK(emfc
->iflist_lock
);
197 /* Flood the frame on to user specified ports */
198 for (ptr
= emfc
->iflist_head
; ptr
!= NULL
; ptr
= ptr
->next
)
202 /* Dont forward the frame on to the port on which it
208 if (proto
== IP_PROT_IGMP
)
210 /* Dont forward IGMP frame if the port is not router port */
211 if (ptr
->rtport_ref
== 0)
216 /* Dont forward data frame if the port is neither router
219 if ((ptr
->rtport_ref
+ ptr
->uffp_ref
) == 0)
223 if ((sdu_clone
= PKTDUP(emfc
->osh
, sdu
)) == NULL
)
225 EMFC_PROT_STATS_INCR(emfc
, proto
, igmp_frames_dropped
,
227 OSL_UNLOCK(emfc
->iflist_lock
);
231 EMF_RELOCK(emfc
->iflist_lock
);
232 res
= emfc
->wrapper
.forward_fn(emfc
->emfi
, sdu_clone
, dest_ip
,
234 OSL_RELOCK(emfc
->iflist_lock
);
237 EMF_INFO("Unable to flood the unreg frame on to %s\n",
238 DEV_IFNAME(ptr
->ifp
));
239 EMFC_PROT_STATS_INCR(emfc
, proto
, igmp_frames_dropped
,
246 OSL_UNLOCK(emfc
->iflist_lock
);
248 if (mcast_flooded
> 0)
250 EMFC_PROT_STATS_INCR(emfc
, proto
, igmp_frames_fwd
,
257 EMFC_PROT_STATS_INCR(emfc
, proto
, igmp_frames_dropped
,
262 PKTFREE(emfc
->osh
, sdu
, FALSE
);
268 * Description: This function is called from the registered OS hook
269 * points once for every frame. This function does the
270 * MFDB lookup, packet cloning and frame forwarding.
272 * Input: emfc - EMFC Global instance data
273 * sdu - Pointer to packet buffer.
274 * ifp - Interface on which the packet arrived.
275 * iph - Pointer to start of IP header.
276 * rt_port - TRUE when the packet is received from IP
277 * Stack otherwise FALSE.
279 * Return: EMF_NOP - No processing needed by EMF, just return
281 * EMF_TAKEN - EMF has taken the ownership of the packet.
282 * EMF_DROP - Drop and free the packet.
285 emfc_input(emfc_info_t
*emfc
, void *sdu
, void *ifp
, uint8
*iph
, bool rt_port
)
289 EMF_DEBUG("Received frame with dest ip %d.%d.%d.%d\n",
290 iph
[IPV4_DEST_IP_OFFSET
], iph
[IPV4_DEST_IP_OFFSET
+ 1],
291 iph
[IPV4_DEST_IP_OFFSET
+ 2], iph
[IPV4_DEST_IP_OFFSET
+ 3]);
293 dest_ip
= ntoh32(*((uint32
*)(iph
+ IPV4_DEST_IP_OFFSET
)));
295 /* No processing is required if the received frame is unicast or
296 * broadcast, when EMF is disabled. Send the frame back to bridge.
298 if ((!IP_ISMULTI(dest_ip
)) || (!emfc
->emf_enable
))
300 EMF_DEBUG("Unicast frame recevied/EMF disabled\n");
304 /* Non-IPv4 multicast packets are not handled */
305 if (IP_VER(iph
) != IP_VER_4
)
307 EMF_INFO("Non-IPv4 multicast packets will be flooded\n");
311 /* Check the protocol type of multicast frame */
312 if ((IPV4_PROT(iph
) == IP_PROT_IGMP
) && (emfc
->snooper
!= NULL
))
316 EMF_DEBUG("Received IGMP frame type %d\n", *(iph
+ IPV4_HLEN(iph
)));
318 EMFC_STATS_INCR(emfc
, igmp_frames
);
320 /* IGMP packet received from LAN or IP Stack. Call the IGMP
321 * Snooping function. Based on the IGMP packet type it may
322 * add/delete MFDB entry. Also the function return value
323 * tells whether to drop, forward, or flood the frame.
325 ASSERT(emfc
->snooper
->input_fn
);
326 action
= emfc
->snooper
->input_fn(emfc
->snooper
, ifp
, iph
,
327 iph
+ IPV4_HLEN(iph
), rt_port
);
332 EMF_INFO("Dropping the IGMP frame\n");
336 emfc
->wrapper
.sendup_fn(emfc
->emfi
, sdu
);
337 EMFC_STATS_INCR(emfc
, igmp_frames_sentup
);
341 return (emfc_unreg_frame_handle(emfc
, sdu
, ifp
,
346 EMF_DEBUG("Returning the IGMP frame to bridge\n");
347 EMFC_STATS_INCR(emfc
, igmp_frames_fwd
);
351 EMF_ERROR("Unknown return value from IGMP Snooper\n");
352 EMFC_STATS_INCR(emfc
, igmp_frames_fwd
);
366 EMF_DEBUG("Received frame with proto %d\n", IPV4_PROT(iph
));
368 EMFC_STATS_INCR(emfc
, mcast_data_frames
);
370 /* Packets with destination IP address in the range 224.0.0.x
371 * must be forwarded on all ports. Similarly UPnP specific
372 * protocol traffic such as SSDP must be forwarded on to all
375 if (MCAST_ADDR_LINKLOCAL(dest_ip
) || MCAST_ADDR_UPNP_SSDP(dest_ip
))
377 EMF_DEBUG("Flooding the frames with link-local/ssdp address\n");
381 OSL_LOCK(emfc
->fdb_lock
);
383 /* Do the MFDB lookup to determine the destination port(s)
384 * to forward the frame.
386 mgrp
= emfc_mfdb_group_find(emfc
, dest_ip
);
388 /* If no matching MFDB entry is found send the frame back to
389 * bridge module so that it floods on to all the ports.
393 OSL_UNLOCK(emfc
->fdb_lock
);
394 EMF_DEBUG("MFDB Group entry not found\n");
395 return (emfc_unreg_frame_handle(emfc
, sdu
, ifp
,
400 ASSERT(!clist_empty(&mgrp
->mi_head
));
402 /* If the data frame is received from one of the bridge
403 * ports then a copy has to be sent up to the router port.
407 EMF_DEBUG("Sending to router port\n");
409 if ((sdu_clone
= PKTDUP(emfc
->osh
, sdu
)) == NULL
)
411 OSL_UNLOCK(emfc
->fdb_lock
);
412 EMFC_STATS_INCR(emfc
, mcast_data_dropped
);
416 EMF_RELOCK(emfc
->fdb_lock
);
417 emfc
->wrapper
.sendup_fn(emfc
->emfi
, sdu_clone
);
418 OSL_RELOCK(emfc
->fdb_lock
);
419 EMFC_STATS_INCR(emfc
, mcast_data_sentup
);
422 /* Data frame received from LAN or IP Stack (WAN). Clone
423 * the buffer and send on all but the last interface.
425 for (ptr
= mgrp
->mi_head
.next
;
426 ptr
!= mgrp
->mi_head
.prev
; ptr
= ptr
->next
)
428 mi
= clist_entry(ptr
, emfc_mi_t
, mi_list
);
430 /* Dont forward the frame on to the port on which it
433 if (ifp
== mi
->mi_mhif
->mhif_ifp
)
436 EMF_DEBUG("Cloning the buffer for forwarding\n");
438 if ((sdu_clone
= PKTDUP(emfc
->osh
, sdu
)) == NULL
)
440 OSL_UNLOCK(emfc
->fdb_lock
);
441 EMFC_STATS_INCR(emfc
, mcast_data_dropped
);
445 EMF_RELOCK(emfc
->fdb_lock
);
446 res
= emfc
->wrapper
.forward_fn(emfc
->emfi
, sdu_clone
,
447 dest_ip
, mi
->mi_mhif
->mhif_ifp
, rt_port
);
448 OSL_RELOCK(emfc
->fdb_lock
);
449 res
? EMFC_STATS_INCR(emfc
, mcast_data_dropped
) :
450 mi
->mi_mhif
->mhif_data_fwd
++,
454 /* Send the last frame without cloning */
455 mi
= clist_entry(ptr
, emfc_mi_t
, mi_list
);
457 /* Dont forward the frame on to the port on which it was received */
458 if (ifp
!= mi
->mi_mhif
->mhif_ifp
)
460 EMF_DEBUG("Sending the original packet buffer\n");
462 EMF_RELOCK(emfc
->fdb_lock
);
463 res
= emfc
->wrapper
.forward_fn(emfc
->emfi
, sdu
, dest_ip
,
464 mi
->mi_mhif
->mhif_ifp
, rt_port
);
465 OSL_RELOCK(emfc
->fdb_lock
);
466 res
? EMFC_STATS_INCR(emfc
, mcast_data_dropped
) :
467 mi
->mi_mhif
->mhif_data_fwd
++,
472 EMF_DEBUG("Freeing the original packet buffer\n");
473 PKTFREE(emfc
->osh
, sdu
, FALSE
);
476 EMFC_STATS_INCR(emfc
, mcast_data_fwd
);
478 OSL_UNLOCK(emfc
->fdb_lock
);
485 * Description: This function initializes the MFDB. MFDB group
486 * entries are organized as a hash table with chaining
487 * for collision resolution. Each MFDB group entry
488 * points to the chain of MFDB interface entries that are
489 * members of the group.
491 * Input: emfc - EMFL Common code global data handle
494 emfc_mfdb_init(emfc_info_t
*emfc
)
498 /* Initialize the multicast forwarding database */
499 for (i
= 0; i
< MFDB_HASHT_SIZE
; i
++)
501 clist_init_head(&emfc
->mgrp_fdb
[i
]);
504 /* Initialize the multicast interface list. This list contains
505 * all the interfaces that have multicast group members. Entries in
506 * this list are never expired/deleted. Each entry maintains stats
507 * specific to the interface.
509 emfc
->mhif_head
= NULL
;
515 * Description: This function does the MFDB lookup to locate interface
516 * entry of the specified group.
518 * Input: emfc - EMFL Common code global data handle
519 * mgrp - Pointer to multicast group entry of MFDB
520 * ifp - Interface pointer to locate.
522 * Return: Returns pointer to the MFDB interface entry, NULL
526 emfc_mfdb_mi_entry_find(emfc_info_t
*emfc
, emfc_mgrp_t
*mgrp
, void *ifp
)
533 for (ptr
= mgrp
->mi_head
.next
;
534 ptr
!= &mgrp
->mi_head
; ptr
= ptr
->next
)
536 mi
= clist_entry(ptr
, emfc_mi_t
, mi_list
);
537 if (ifp
== mi
->mi_mhif
->mhif_ifp
)
547 * Description: This function does the MFDB lookup to locate a multicast
550 * Input: emfc - EMFL Common code global data handle
551 * mgrp_ip - Multicast group address of the entry.
553 * Return: Returns NULL is no group entry is found. Otherwise
554 * returns pointer to the MFDB group entry.
557 emfc_mfdb_group_find(emfc_info_t
*emfc
, uint32 mgrp_ip
)
563 ASSERT(IP_ISMULTI(mgrp_ip
));
565 /* Do the cache lookup first. Since the multicast video traffic
566 * is bursty in nature there is a good chance that the cache
567 * hit ratio will be good. If during the testing we find that
568 * the hit ratio is not as good then this single entry cache
569 * mechanism will be removed.
571 if (mgrp_ip
== emfc
->mgrp_cache_ip
)
573 EMFC_STATS_INCR(emfc
, mfdb_cache_hits
);
574 return (emfc
->mgrp_cache
);
577 EMFC_STATS_INCR(emfc
, mfdb_cache_misses
);
579 hash
= MFDB_MGRP_HASH(mgrp_ip
);
581 for (ptr
= emfc
->mgrp_fdb
[hash
].next
;
582 ptr
!= &emfc
->mgrp_fdb
[hash
];
585 mgrp
= clist_entry(ptr
, emfc_mgrp_t
, mgrp_hlist
);
587 /* Compare group address */
588 if (mgrp_ip
== mgrp
->mgrp_ip
)
590 EMF_MFDB("Multicast Group entry %d.%d.%d.%d found\n",
591 (mgrp_ip
>> 24), ((mgrp_ip
>> 16) & 0xff),
592 ((mgrp_ip
>> 8) & 0xff), (mgrp_ip
& 0xff));
593 emfc
->mgrp_cache
= mgrp
;
594 emfc
->mgrp_cache_ip
= mgrp_ip
;
603 * Add the entry if not present otherwise return the pointer to
607 emfc_mfdb_mhif_add(emfc_info_t
*emfc
, void *ifp
)
609 emfc_mhif_t
*ptr
, *mhif
;
611 for (ptr
= emfc
->mhif_head
; ptr
!= NULL
; ptr
= ptr
->next
)
613 if (ptr
->mhif_ifp
== ifp
)
620 mhif
= MALLOC(emfc
->osh
, sizeof(emfc_mhif_t
));
623 EMF_ERROR("Failed to alloc mem size %d for mhif entry\n",
624 sizeof(emfc_mhif_t
));
628 mhif
->mhif_ifp
= ifp
;
629 mhif
->mhif_data_fwd
= 0;
630 mhif
->next
= emfc
->mhif_head
;
631 emfc
->mhif_head
= mhif
;
637 * Description: This function does the MFDB lookup to locate a interface
638 * entry of the specified multicast group.
640 * Input: emfc - EMFL Common code global data handle
641 * mgrp_ip - Multicast group IP address of the entry.
642 * ifp - Pointer to the interface on which the member
645 * Return: Returns NULL is no interface entry is found. Otherwise
646 * returns pointer to the MFDB interface entry.
649 emfc_mfdb_membership_find(emfc_info_t
*emfc
, uint32 mgrp_ip
, void *ifp
)
654 ASSERT(IP_ISMULTI(mgrp_ip
));
656 OSL_LOCK(emfc
->fdb_lock
);
658 /* Find group entry */
659 mgrp
= emfc_mfdb_group_find(emfc
, mgrp_ip
);
663 /* Find interface entry */
664 mi
= emfc_mfdb_mi_entry_find(emfc
, mgrp
, ifp
);
667 EMF_MFDB("Interface entry %d.%d.%d.%d:%p found\n",
668 (mgrp_ip
>> 24), ((mgrp_ip
>> 16) & 0xff),
669 ((mgrp_ip
>> 8) & 0xff), (mgrp_ip
& 0xff), ifp
);
674 OSL_UNLOCK(emfc
->fdb_lock
);
676 EMF_MFDB("Interface entry %x %p not found\n", mgrp_ip
, ifp
);
682 * Description: This function is called by IGMP Snooper when it wants
683 * to add MFDB entry or refresh the entry. This function
684 * is also called by the management application to add a
687 * If the MFDB entry is not present, it allocates group
688 * entry, interface entry and links them together.
690 * Input: Same as above function.
692 * Return: SUCCESS or FAILURE
695 emfc_mfdb_membership_add(emfc_info_t
*emfc
, uint32 mgrp_ip
, void *ifp
)
701 ASSERT(IP_ISMULTI(mgrp_ip
));
703 OSL_LOCK(emfc
->fdb_lock
);
705 /* If the group entry doesn't exist, add a new entry and update
706 * the member/interface information.
708 mgrp
= emfc_mfdb_group_find(emfc
, mgrp_ip
);
712 /* Allocate and initialize multicast group entry */
713 mgrp
= MALLOC(emfc
->osh
, sizeof(emfc_mgrp_t
));
716 EMF_ERROR("Failed to alloc mem size %d for group entry\n",
717 sizeof(emfc_mgrp_t
));
718 OSL_UNLOCK(emfc
->fdb_lock
);
722 mgrp
->mgrp_ip
= mgrp_ip
;
723 clist_init_head(&mgrp
->mi_head
);
725 EMF_MFDB("Adding group entry %d.%d.%d.%d\n",
726 (mgrp_ip
>> 24), ((mgrp_ip
>> 16) & 0xff),
727 ((mgrp_ip
>> 8) & 0xff), (mgrp_ip
& 0xff));
729 /* Add the group entry to hash table */
730 hash
= MFDB_MGRP_HASH(mgrp_ip
);
731 clist_add_head(&emfc
->mgrp_fdb
[hash
], &mgrp
->mgrp_hlist
);
735 mi
= emfc_mfdb_mi_entry_find(emfc
, mgrp
, ifp
);
737 /* Update the ref count */
741 OSL_UNLOCK(emfc
->fdb_lock
);
746 EMF_MFDB("Adding interface entry for interface %p\n", ifp
);
748 /* Allocate and initialize multicast interface entry */
749 mi
= MALLOC(emfc
->osh
, sizeof(emfc_mi_t
));
752 EMF_ERROR("Failed to allocated memory %d for interface entry\n",
754 if (clist_empty(&mgrp
->mi_head
))
756 clist_delete(&mgrp
->mgrp_hlist
);
757 emfc
->mgrp_cache_ip
= ((emfc
->mgrp_cache
== mgrp
) ?
758 0 : emfc
->mgrp_cache_ip
);
759 MFREE(emfc
->osh
, mgrp
, sizeof(emfc_mgrp_t
));
761 OSL_UNLOCK(emfc
->fdb_lock
);
765 /* Initialize the multicast interface list entry */
767 mi
->mi_mhif
= emfc_mfdb_mhif_add(emfc
, ifp
);
770 /* Add the multicast interface entry */
771 clist_add_head(&mgrp
->mi_head
, &mi
->mi_list
);
773 OSL_UNLOCK(emfc
->fdb_lock
);
779 * Description: This function is called by the IGMP snooper layer
780 * to delete the MFDB entry. It deletes the group
781 * entry also if the interface entry is last in the
784 * Input: Same as above function.
786 * Return: SUCCESS or FAILURE
789 emfc_mfdb_membership_del(emfc_info_t
*emfc
, uint32 mgrp_ip
, void *ifp
)
794 OSL_LOCK(emfc
->fdb_lock
);
796 /* Find group entry */
797 mgrp
= emfc_mfdb_group_find(emfc
, mgrp_ip
);
801 OSL_UNLOCK(emfc
->fdb_lock
);
805 /* Find interface entry */
806 mi
= emfc_mfdb_mi_entry_find(emfc
, mgrp
, ifp
);
810 OSL_UNLOCK(emfc
->fdb_lock
);
814 EMF_MFDB("Deleting MFDB interface entry for interface %p\n", ifp
);
816 /* Delete the interface entry when ref count reaches zero */
820 OSL_UNLOCK(emfc
->fdb_lock
);
825 EMF_MFDB("Deleting interface entry %p\n", mi
->mi_mhif
->mhif_ifp
);
826 clist_delete(&mi
->mi_list
);
829 /* If the member being deleted is last node in the interface list,
830 * delete the group entry also.
832 if (clist_empty(&mgrp
->mi_head
))
834 EMF_MFDB("Deleting group entry of %d.%d.%d.%d too\n",
835 (mgrp_ip
>> 24), ((mgrp_ip
>> 16) & 0xff),
836 ((mgrp_ip
>> 8) & 0xff), (mgrp_ip
& 0xff));
838 clist_delete(&mgrp
->mgrp_hlist
);
839 emfc
->mgrp_cache_ip
= ((emfc
->mgrp_cache
== mgrp
) ?
840 0 : emfc
->mgrp_cache_ip
);
841 MFREE(emfc
->osh
, mgrp
, sizeof(emfc_mgrp_t
));
844 MFREE(emfc
->osh
, mi
, sizeof(emfc_mi_t
));
846 OSL_UNLOCK(emfc
->fdb_lock
);
852 * Description: This function clears the group interval timers and
853 * deletes the group and interface entries of the MFDB.
855 * Input: emfc - EMFL Common code global data handle
858 emfc_mfdb_clear(emfc_info_t
*emfc
)
863 clist_head_t
*ptr1
, *ptr2
, *tmp1
, *tmp2
;
865 OSL_LOCK(emfc
->fdb_lock
);
867 /* Delete all the group entries */
868 for (i
= 0; i
< MFDB_HASHT_SIZE
; i
++)
870 for (ptr1
= emfc
->mgrp_fdb
[i
].next
;
871 ptr1
!= &emfc
->mgrp_fdb
[i
]; ptr1
= tmp1
)
873 mgrp
= clist_entry(ptr1
, emfc_mgrp_t
, mgrp_hlist
);
875 /* Delete all interface entries */
876 for (ptr2
= mgrp
->mi_head
.next
;
877 ptr2
!= &mgrp
->mi_head
; ptr2
= tmp2
)
879 mi
= clist_entry(ptr2
, emfc_mi_t
, mi_list
);
882 EMF_MFDB("Deleting interface entry %p\n", mi
);
884 MFREE(emfc
->osh
, mi
, sizeof(emfc_mi_t
));
889 /* Delete the group entry when there are no more interface
890 * entries for this group.
893 MFREE(emfc
->osh
, mgrp
, sizeof(emfc_mgrp_t
));
897 emfc
->mgrp_cache_ip
= 0;
899 OSL_UNLOCK(emfc
->fdb_lock
);
905 * EMFC Interface List cleanup
908 emfc_iflist_clear(emfc_info_t
*emfc
)
910 emfc_iflist_t
*ptr
, *temp
;
912 OSL_LOCK(emfc
->iflist_lock
);
914 ptr
= emfc
->iflist_head
;
918 MFREE(emfc
->osh
, ptr
, sizeof(emfc_iflist_t
));
922 emfc
->iflist_head
= NULL
;
924 OSL_UNLOCK(emfc
->iflist_lock
);
930 * Description: This function is called to enable/disable the efficient
931 * multicast forwarding feature. When the config operation
932 * cannot be completed respective status is returned.
934 * Input: emfc - EMFL Common code global data handle
936 * Input/Output: cfg - Pointer to configuration request data. It contains
937 * the command id, operation type, corresponding
938 * arguments and output status.
941 emfc_cfg_emf_enable(emfc_info_t
*emfc
, emf_cfg_request_t
*cfg
)
945 EMF_DEBUG("Operation type: %d\n", cfg
->oper_type
);
947 switch (cfg
->oper_type
)
949 case EMFCFG_OPER_TYPE_GET
:
950 *(bool *)cfg
->arg
= emfc
->emf_enable
;
951 cfg
->size
= sizeof(bool);
952 cfg
->status
= EMFCFG_STATUS_SUCCESS
;
955 case EMFCFG_OPER_TYPE_SET
:
956 /* Enable or disable EMF */
957 emf_enable
= (*(bool *)cfg
->arg
? TRUE
: FALSE
);
958 if (emfc
->emf_enable
== emf_enable
)
960 cfg
->status
= EMFCFG_STATUS_FAILURE
;
961 cfg
->size
= sprintf(cfg
->arg
,
962 "Duplicate configuration request\n");
966 emfc
->emf_enable
= emf_enable
;
968 if (emfc
->emf_enable
)
970 /* Register the hooks to start receiving multicast frames */
971 if (emfc
->wrapper
.hooks_register_fn(emfc
->emfi
) != SUCCESS
)
973 cfg
->status
= EMFCFG_STATUS_FAILURE
;
974 cfg
->size
= sprintf(cfg
->arg
,
975 "Duplicate hooks registration\n");
979 /* Call the registered EMF enable entry point function */
980 if (emfc
->snooper
&& emfc
->snooper
->emf_enable_fn
!= NULL
)
982 EMF_DEBUG("Calling the EMF enable function\n");
983 emfc
->snooper
->emf_enable_fn(emfc
->snooper
);
988 /* Call the registered EMF disable entry point function */
989 if (emfc
->snooper
&& emfc
->snooper
->emf_disable_fn
!= NULL
)
991 EMF_DEBUG("Calling the EMF disable function\n");
992 emfc
->snooper
->emf_disable_fn(emfc
->snooper
);
995 /* Unregister the packet hooks first */
996 emfc
->wrapper
.hooks_unregister_fn(emfc
->emfi
);
998 /* Cleanup the MFDB entries */
999 emfc_mfdb_clear(emfc
);
1001 /* Cleanup the UFFP entries */
1002 emfc_iflist_clear(emfc
);
1005 cfg
->status
= EMFCFG_STATUS_SUCCESS
;
1009 cfg
->status
= EMFCFG_STATUS_OPER_UNKNOWN
;
1010 cfg
->size
= sprintf(cfg
->arg
, "Unknown operation\n");
1018 * EMFL Packet Counters/Statistics
1021 emfc_stats_get(emfc_info_t
*emfc
, emf_stats_t
*emfs
, uint32 size
)
1025 EMF_ERROR("Invalid EMFC handle passed\n");
1031 EMF_ERROR("Invalid buffer input\n");
1035 if (size
< sizeof(emf_stats_t
))
1037 EMF_ERROR("Insufficient buffer size %d\n", size
);
1041 *emfs
= emfc
->stats
;
1047 * MFDB Listing Function
1050 emfc_mfdb_list(emfc_info_t
*emfc
, emf_cfg_mfdb_list_t
*list
, uint32 size
)
1052 clist_head_t
*ptr1
, *ptr2
;
1059 EMF_ERROR("Invalid EMFC handle passed\n");
1065 EMF_ERROR("Invalid buffer input\n");
1069 for (i
= 0; i
< MFDB_HASHT_SIZE
; i
++)
1071 for (ptr1
= emfc
->mgrp_fdb
[i
].next
;
1072 ptr1
!= &emfc
->mgrp_fdb
[i
]; ptr1
= ptr1
->next
)
1074 mgrp
= clist_entry(ptr1
, emfc_mgrp_t
, mgrp_hlist
);
1075 for (ptr2
= mgrp
->mi_head
.next
;
1076 ptr2
!= &mgrp
->mi_head
; ptr2
= ptr2
->next
)
1078 mi
= clist_entry(ptr2
, emfc_mi_t
, mi_list
);
1080 list
->mfdb_entry
[index
].mgrp_ip
= mgrp
->mgrp_ip
;
1081 strncpy(list
->mfdb_entry
[index
].if_name
,
1082 DEV_IFNAME(mi
->mi_mhif
->mhif_ifp
), 16);
1083 list
->mfdb_entry
[index
].pkts_fwd
= mi
->mi_data_fwd
;
1089 /* Update the total number of entries */
1090 list
->num_entries
= index
;
1096 * EMFC Interface List find
1098 static emfc_iflist_t
*
1099 emfc_iflist_find(emfc_info_t
*emfc
, void *ifp
, emfc_iflist_t
**prev
)
1103 OSL_LOCK(emfc
->iflist_lock
);
1106 for (ptr
= emfc
->iflist_head
; ptr
!= NULL
;
1107 *prev
= ptr
, ptr
= ptr
->next
)
1109 if (ptr
->ifp
== ifp
)
1111 OSL_UNLOCK(emfc
->iflist_lock
);
1116 OSL_UNLOCK(emfc
->iflist_lock
);
1122 * EMFC Interface List add entry
1125 emfc_iflist_add(emfc_info_t
*emfc
, void *ifp
)
1127 emfc_iflist_t
*iflist
, *prev
;
1131 EMF_ERROR("Invalid interface identifier\n");
1135 if (emfc_iflist_find(emfc
, ifp
, &prev
) != NULL
)
1137 EMF_DEBUG("Adding duplicate interface entry\n");
1141 /* Allocate and initialize UFFP entry */
1142 iflist
= MALLOC(emfc
->osh
, sizeof(emfc_iflist_t
));
1145 EMF_ERROR("Failed to alloc mem size %d for interface entry\n",
1146 sizeof(emfc_iflist_t
));
1151 iflist
->uffp_ref
= 0;
1152 iflist
->rtport_ref
= 0;
1154 /* Add the UFFP entry to the list */
1155 OSL_LOCK(emfc
->iflist_lock
);
1156 iflist
->next
= emfc
->iflist_head
;
1157 emfc
->iflist_head
= iflist
;
1158 OSL_UNLOCK(emfc
->iflist_lock
);
1164 * EMFC Interface List delete entry
1167 emfc_iflist_del(emfc_info_t
*emfc
, void *ifp
)
1169 emfc_iflist_t
*ptr
, *prev
;
1173 EMF_ERROR("Invalid interface identifier\n");
1177 if ((ptr
= emfc_iflist_find(emfc
, ifp
, &prev
)) == NULL
)
1179 EMF_ERROR("UFFP entry not found\n");
1183 OSL_LOCK(emfc
->iflist_lock
);
1185 /* Delete the UFFP entry from the list */
1187 prev
->next
= ptr
->next
;
1189 emfc
->iflist_head
= ptr
->next
;
1191 OSL_UNLOCK(emfc
->iflist_lock
);
1193 MFREE(emfc
->osh
, ptr
, sizeof(emfc_iflist_t
));
1202 emfc_uffp_add(emfc_info_t
*emfc
, void *ifp
)
1204 emfc_iflist_t
*iflist
, *prev
;
1206 /* Add the interface entry if not present already */
1207 emfc_iflist_add(emfc
, ifp
);
1209 OSL_LOCK(emfc
->iflist_lock
);
1210 if ((iflist
= emfc_iflist_find(emfc
, ifp
, &prev
)) != NULL
)
1212 OSL_UNLOCK(emfc
->iflist_lock
);
1221 emfc_uffp_del(emfc_info_t
*emfc
, void *ifp
)
1223 emfc_iflist_t
*iflist
, *prev
;
1225 if ((iflist
= emfc_iflist_find(emfc
, ifp
, &prev
)) == NULL
)
1228 /* Delete the interface entry when flags is zero */
1229 OSL_LOCK(emfc
->iflist_lock
);
1231 if ((iflist
->uffp_ref
== 0) && (iflist
->rtport_ref
== 0))
1232 emfc_iflist_del(emfc
, ifp
);
1233 OSL_UNLOCK(emfc
->iflist_lock
);
1239 * UFFP Interface Listing
1242 emfc_uffp_list(emfc_info_t
*emfc
, emf_cfg_uffp_list_t
*list
, uint32 size
)
1244 int32 index
= 0, bytes
= 0;
1247 for (ptr
= emfc
->iflist_head
; ptr
!= NULL
; ptr
= ptr
->next
)
1249 if (ptr
->uffp_ref
== 0)
1252 bytes
+= sizeof(emf_cfg_uffp_t
);
1256 strncpy(list
->uffp_entry
[index
].if_name
, DEV_IFNAME(ptr
->ifp
), 16);
1257 list
->uffp_entry
[index
].if_name
[15] = 0;
1261 /* Update the total number of entries */
1262 list
->num_entries
= index
;
1268 * Description: This function is called by the IGMP Snooper to add a Router
1269 * Port. Router Port is the interface on which the IGMP Snooper
1270 * determines that a multicast router is present. We set a bit
1271 * in the flag field of the interface list entry to mark it as
1274 * Input: emfc - EMFC Global Instance handle
1275 * ifp - Interface pointer
1277 * Return: SUCCESS/FAILURE
1280 emfc_rtport_add(emfc_info_t
*emfc
, void *ifp
)
1282 emfc_iflist_t
*iflist
, *prev
;
1284 /* Add interface list entry */
1285 emfc_iflist_add(emfc
, ifp
);
1287 OSL_LOCK(emfc
->iflist_lock
);
1288 if ((iflist
= emfc_iflist_find(emfc
, ifp
, &prev
)) != NULL
)
1289 iflist
->rtport_ref
++;
1290 OSL_UNLOCK(emfc
->iflist_lock
);
1292 EMF_INFO("RTPORT %s added refcount %d\n", DEV_IFNAME(ifp
), iflist
->rtport_ref
);
1298 * Description: This function is called by the IGMP Snooper to delete a
1299 * Router Port. We clear the corresponding bit in the flags
1300 * field to mark the port as non-router port.
1302 * Input: emfc - EMFC Global Instance handle
1303 * ifp - Interface pointer
1305 * Return: SUCCESS/FAILURE
1308 emfc_rtport_del(emfc_info_t
*emfc
, void *ifp
)
1310 emfc_iflist_t
*iflist
, *prev
;
1312 if ((iflist
= emfc_iflist_find(emfc
, ifp
, &prev
)) == NULL
)
1314 EMF_ERROR("Invalid interface specified to rtport delete\n");
1318 /* Delete the interface entry when flags is zero */
1319 OSL_LOCK(emfc
->iflist_lock
);
1320 iflist
->rtport_ref
--;
1321 if ((iflist
->rtport_ref
== 0) && (iflist
->uffp_ref
== 0))
1322 emfc_iflist_del(emfc
, ifp
);
1323 OSL_UNLOCK(emfc
->iflist_lock
);
1329 * RTPORT listing function
1332 emfc_rtport_list(emfc_info_t
*emfc
, emf_cfg_rtport_list_t
*list
, uint32 size
)
1334 int32 index
= 0, bytes
= 0;
1337 for (ptr
= emfc
->iflist_head
; ptr
!= NULL
; ptr
= ptr
->next
)
1339 if (ptr
->rtport_ref
== 0)
1342 bytes
+= sizeof(emf_cfg_rtport_t
);
1346 strncpy(list
->rtport_entry
[index
].if_name
, DEV_IFNAME(ptr
->ifp
), 16);
1347 list
->rtport_entry
[index
].if_name
[15] = 0;
1351 /* Update the total number of entries */
1352 list
->num_entries
= index
;
1358 * Description: This function is called from the OS Specific layer when the
1359 * user issues a configuration command.
1361 * Input/Output: Same as emfc_cfg_emf_enable.
1364 emfc_cfg_request_process(emfc_info_t
*emfc
, emf_cfg_request_t
*cfg
)
1366 emf_cfg_mfdb_t
*mfdb
;
1367 emf_cfg_uffp_t
*uffp
;
1368 emf_cfg_rtport_t
*rtport
;
1370 EMF_DEBUG("Command identifier: %d\n", cfg
->command_id
);
1372 switch (cfg
->command_id
)
1374 case EMFCFG_CMD_EMF_ENABLE
:
1375 emfc_cfg_emf_enable(emfc
, cfg
);
1378 case EMFCFG_CMD_MFDB_ADD
:
1379 mfdb
= (emf_cfg_mfdb_t
*)cfg
->arg
;
1382 /* Add MFDB entry for this group and interface */
1383 if (emfc_mfdb_membership_add(emfc
, mfdb
->mgrp_ip
,
1384 mfdb
->if_ptr
) != SUCCESS
)
1386 cfg
->status
= EMFCFG_STATUS_FAILURE
;
1387 cfg
->size
+= sprintf(cfg
->arg
, "Unable to add entry\n");
1391 cfg
->status
= EMFCFG_STATUS_SUCCESS
;
1393 EMF_MFDB("MFDB entry %x %p added by user\n",
1394 mfdb
->mgrp_ip
, mfdb
->if_ptr
);
1397 case EMFCFG_CMD_MFDB_DEL
:
1398 mfdb
= (emf_cfg_mfdb_t
*)cfg
->arg
;
1401 /* Delete MFDB entry */
1402 if (emfc_mfdb_membership_del(emfc
, mfdb
->mgrp_ip
,
1403 mfdb
->if_ptr
) != SUCCESS
)
1405 cfg
->status
= EMFCFG_STATUS_FAILURE
;
1406 cfg
->size
+= sprintf(cfg
->arg
, "MFDB entry not found\n");
1410 cfg
->status
= EMFCFG_STATUS_SUCCESS
;
1412 EMF_MFDB("MFDB entry %x %p deleted by user\n",
1413 mfdb
->mgrp_ip
, mfdb
->if_ptr
);
1416 case EMFCFG_CMD_MFDB_LIST
:
1417 if (emfc_mfdb_list(emfc
, (emf_cfg_mfdb_list_t
*)cfg
->arg
,
1418 cfg
->size
) != SUCCESS
)
1420 cfg
->status
= EMFCFG_STATUS_FAILURE
;
1421 cfg
->size
+= sprintf(cfg
->arg
, "MFDB list get failed\n");
1425 cfg
->status
= EMFCFG_STATUS_SUCCESS
;
1428 case EMFCFG_CMD_MFDB_CLEAR
:
1429 emfc_mfdb_clear(emfc
);
1430 cfg
->status
= EMFCFG_STATUS_SUCCESS
;
1433 case EMFCFG_CMD_RTPORT_ADD
:
1434 rtport
= (emf_cfg_rtport_t
*)cfg
->arg
;
1437 if (emfc_rtport_add(emfc
, rtport
->if_ptr
) != SUCCESS
)
1439 cfg
->status
= EMFCFG_STATUS_FAILURE
;
1440 cfg
->size
+= sprintf(cfg
->arg
,
1441 "Unknown interface, rtport add failed\n");
1445 cfg
->status
= EMFCFG_STATUS_SUCCESS
;
1448 case EMFCFG_CMD_RTPORT_DEL
:
1449 rtport
= (emf_cfg_rtport_t
*)cfg
->arg
;
1452 if (emfc_rtport_del(emfc
, rtport
->if_ptr
) != SUCCESS
)
1454 cfg
->status
= EMFCFG_STATUS_FAILURE
;
1455 cfg
->size
+= sprintf(cfg
->arg
,
1456 "Unknown interface, rtport del failed\n");
1460 cfg
->status
= EMFCFG_STATUS_SUCCESS
;
1463 case EMFCFG_CMD_RTPORT_LIST
:
1464 if (emfc_rtport_list(emfc
, (emf_cfg_rtport_list_t
*)cfg
->arg
,
1465 cfg
->size
) != SUCCESS
)
1467 cfg
->status
= EMFCFG_STATUS_FAILURE
;
1468 cfg
->size
= sprintf(cfg
->arg
, "rtport list get failed\n");
1472 cfg
->status
= EMFCFG_STATUS_SUCCESS
;
1475 case EMFCFG_CMD_UFFP_ADD
:
1476 uffp
= (emf_cfg_uffp_t
*)cfg
->arg
;
1479 if (emfc_uffp_add(emfc
, uffp
->if_ptr
) != SUCCESS
)
1481 cfg
->status
= EMFCFG_STATUS_FAILURE
;
1482 cfg
->size
+= sprintf(cfg
->arg
,
1483 "Unknown interface, UFFP add failed\n");
1487 cfg
->status
= EMFCFG_STATUS_SUCCESS
;
1490 case EMFCFG_CMD_UFFP_DEL
:
1491 uffp
= (emf_cfg_uffp_t
*)cfg
->arg
;
1494 if (emfc_uffp_del(emfc
, uffp
->if_ptr
) != SUCCESS
)
1496 cfg
->status
= EMFCFG_STATUS_FAILURE
;
1497 cfg
->size
+= sprintf(cfg
->arg
,
1498 "Unknown interface, UFFP del failed\n");
1502 cfg
->status
= EMFCFG_STATUS_SUCCESS
;
1505 case EMFCFG_CMD_UFFP_LIST
:
1506 if (emfc_uffp_list(emfc
, (emf_cfg_uffp_list_t
*)cfg
->arg
,
1507 cfg
->size
) != SUCCESS
)
1509 cfg
->status
= EMFCFG_STATUS_FAILURE
;
1510 cfg
->size
= sprintf(cfg
->arg
, "UFFP list get failed\n");
1514 cfg
->status
= EMFCFG_STATUS_SUCCESS
;
1517 case EMFCFG_CMD_EMF_STATS
:
1518 if (emfc_stats_get(emfc
, (emf_stats_t
*)cfg
->arg
,
1519 cfg
->size
) != SUCCESS
)
1521 cfg
->status
= EMFCFG_STATUS_FAILURE
;
1522 cfg
->size
= sprintf(cfg
->arg
, "EMF stats get failed\n");
1526 cfg
->status
= EMFCFG_STATUS_SUCCESS
;
1530 EMF_DEBUG("Unknown command %d\n", cfg
->command_id
);
1531 cfg
->status
= EMFCFG_STATUS_CMD_UNKNOWN
;
1532 cfg
->size
= sprintf(cfg
->arg
, "Unknown command\n");
1540 * Description: This function is called from the OS specific module init
1541 * routine to create and initialize EMFC instance. This function
1542 * primarily initializes the EMFL global data and MFDB.
1544 * Input: inst_id - Instance identier used to associate EMF
1545 * and IGMP snooper instances.
1546 * emfi - EMFL OS Specific global data handle
1547 * osh - OS abstraction layer handle
1548 * wrapper - EMFC wrapper info
1550 * Return: emfc - EMFL Common code global data handle
1553 emfc_init(int8
*inst_id
, void *emfi
, osl_t
*osh
, emfc_wrapper_t
*wrapper
)
1557 EMF_DEBUG("Initializing EMFL\n");
1559 /* Check for the wrapper parameter */
1560 if (wrapper
== NULL
)
1562 EMF_ERROR("emfc_init: wrapper parameter NULL\n");
1566 /* Allocate memory */
1567 emfc
= MALLOC(osh
, sizeof(emfc_info_t
));
1570 EMF_ERROR("Failed to allocated memory size %d for MFL\n",
1571 sizeof(emfc_info_t
));
1575 EMF_DEBUG("Allocated memory for EMFC info\n");
1577 /* Initialize the EMF global data */
1578 bzero(emfc
, sizeof(emfc_info_t
));
1581 emfc
->mgrp_cache_ip
= 0;
1582 emfc
->mgrp_cache
= NULL
;
1583 emfc
->iflist_head
= NULL
;
1585 /* Set EMF status as disabled */
1586 emfc
->emf_enable
= FALSE
;
1588 /* Initialize Multicast FDB */
1589 emfc_mfdb_init(emfc
);
1591 /* Create lock for MFDB access */
1592 emfc
->fdb_lock
= OSL_LOCK_CREATE("FDB Lock");
1593 if (emfc
->fdb_lock
== NULL
)
1595 MFREE(emfc
->osh
, emfc
, sizeof(emfc_info_t
));
1599 /* Create lock for router port list access */
1600 emfc
->iflist_lock
= OSL_LOCK_CREATE("Router Port List Lock");
1601 if (emfc
->iflist_lock
== NULL
)
1603 OSL_LOCK_DESTROY(emfc
->fdb_lock
);
1604 MFREE(emfc
->osh
, emfc
, sizeof(emfc_info_t
));
1608 /* Save the instance id */
1609 strncpy(emfc
->inst_id
, inst_id
, IFNAMSIZ
);
1610 emfc
->inst_id
[IFNAMSIZ
- 1] = 0;
1612 /* Fill up the wrapper specific functions */
1613 emfc
->wrapper
.forward_fn
= wrapper
->forward_fn
;
1614 emfc
->wrapper
.sendup_fn
= wrapper
->sendup_fn
;
1615 emfc
->wrapper
.hooks_register_fn
= wrapper
->hooks_register_fn
;
1616 emfc
->wrapper
.hooks_unregister_fn
= wrapper
->hooks_unregister_fn
;
1618 /* Add to the EMFC instance list */
1619 OSL_LOCK(emfc_list_lock
);
1620 clist_add_head(&emfc_list_head
, &emfc
->emfc_list
);
1621 OSL_UNLOCK(emfc_list_lock
);
1623 EMF_DEBUG("Initialized MFDB\n");
1629 * Description: This function is called from OS specific module cleanup
1630 * routine. This routine primarily clears the MFDB entries
1631 * and frees the global instance data.
1633 * Input: emfc - EMFL global instance handle
1636 emfc_exit(emfc_info_t
*emfc
)
1638 emfc_mhif_t
*ptr
, *temp
;
1640 /* Unregister the packet hooks if not already */
1641 emfc
->wrapper
.hooks_unregister_fn(emfc
->emfi
);
1643 /* Cleanup MFDB entries */
1644 emfc_mfdb_clear(emfc
);
1646 /* Cleanup the interface list entries */
1647 emfc_iflist_clear(emfc
);
1648 OSL_LOCK_DESTROY(emfc
->iflist_lock
);
1650 OSL_LOCK(emfc
->fdb_lock
);
1652 /* Delete interface list */
1653 ptr
= emfc
->mhif_head
;
1657 MFREE(emfc
->osh
, ptr
, sizeof(emfc_mhif_t
));
1661 OSL_UNLOCK(emfc
->fdb_lock
);
1663 OSL_LOCK_DESTROY(emfc
->fdb_lock
);
1665 /* Delete the EMFC instance */
1666 OSL_LOCK(emfc_list_lock
);
1667 clist_delete(&emfc
->emfc_list
);
1668 OSL_UNLOCK(emfc_list_lock
);
1670 MFREE(emfc
->osh
, emfc
, sizeof(emfc_info_t
));
1672 EMF_DEBUG("Cleaned up EMFL, exiting common code\n");
1678 * Description: This function is called from OS specific module init
1679 * routine. This allocates global resources required by the
1683 emfc_module_init(void)
1685 /* Create lock for EMFC instance list access */
1686 emfc_list_lock
= OSL_LOCK_CREATE("EMFC List Lock");
1688 if (emfc_list_lock
== NULL
)
1690 EMF_ERROR("EMFC List lock create failed\n");
1698 * Description: This function is called from OS specific module cleanup
1699 * routine. This frees all the global resources.
1702 emfc_module_exit(void)
1704 OSL_LOCK_DESTROY(emfc_list_lock
);