K2.6 patches and update.
[tomato.git] / release / src-rt / emf / emf / emfc.c
blobe8db9ab9824a5d3bdee643cdb4a86706be950d63
1 /*
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 $
19 #include <typedefs.h>
20 #include <bcmdefs.h>
21 #include <bcmendian.h>
22 #include <proto/ethernet.h>
23 #include <proto/bcmip.h>
24 #include <osl.h>
25 #if defined(linux)
26 #include <osl_linux.h>
27 #else /* defined(osl_xx) */
28 #error "Unsupported osl"
29 #endif /* defined(osl_xx) */
30 #include <bcmutils.h>
31 #include "clist.h"
32 #include "emf_cfg.h"
33 #include "emfc_export.h"
34 #include "emfc.h"
35 #include "emf_export.h"
37 /* BH-enabled helpers */
38 #define EMF_RELOCK(lock) do { \
39 OSL_UNLOCK(lock); \
40 spin_lock(&((lock)->slock)); \
41 } while (0)
42 #define OSL_RELOCK(lock) do { \
43 spin_unlock(&((lock)->slock)); \
44 OSL_LOCK(lock); \
45 } while (0)
47 static CLIST_DECL_INIT(emfc_list_head);
48 static osl_lock_t emfc_list_lock;
50 static emfc_info_t *
51 emfc_instance_find(char *inst_id)
53 emfc_info_t *emfc;
54 clist_head_t *ptr;
56 if (inst_id == NULL)
58 EMF_ERROR("Invalid instance id string\n");
59 return (NULL);
62 OSL_LOCK(emfc_list_lock);
64 for (ptr = emfc_list_head.next; ptr != &emfc_list_head;
65 ptr = ptr->next)
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);
72 return (emfc);
76 OSL_UNLOCK(emfc_list_lock);
78 return (NULL);
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
93 * persistent.
95 * Return: SUCCESS or FAILURE
97 int32
98 emfc_igmp_snooper_register(int8 *inst_id, emfc_info_t **emfc, emfc_snooper_t *snooper)
100 /* Invalid input */
101 if (snooper == NULL)
103 EMF_ERROR("Snooper parameter should be non NULL\n");
104 return (FAILURE);
107 if (emfc == NULL)
109 EMF_ERROR("EMF handle should be non NULL\n");
110 return (FAILURE);
113 /* Validate the instance id */
114 if ((*emfc = emfc_instance_find(inst_id)) == NULL)
116 EMF_ERROR("EMF Instance doesn't exist\n");
117 return (FAILURE);
120 if (snooper->input_fn == NULL)
122 EMF_ERROR("Snooper input function should be non NULL\n");
123 return (FAILURE);
126 (*emfc)->snooper = snooper;
128 return (SUCCESS);
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
138 void
139 emfc_igmp_snooper_unregister(emfc_info_t *emfc)
141 if (emfc == NULL)
143 EMF_ERROR("Unregistering using invalid handle\n");
144 return;
147 emfc->snooper = NULL;
149 return;
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
166 * the packet back.
167 * EMF_DROP - Drop and free the packet.
169 static uint32
170 emfc_unreg_frame_handle(emfc_info_t *emfc, void *sdu, void *ifp, uint8 proto,
171 uint32 dest_ip, bool rt_port)
173 emfc_iflist_t *ptr;
174 void *sdu_clone;
175 uint32 mcast_flooded = 0;
177 /* Forward the frame on to router port */
178 if (!rt_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,
185 mcast_data_dropped);
186 return (EMF_DROP);
189 emfc->wrapper.sendup_fn(emfc->emfi, sdu_clone);
191 EMFC_PROT_STATS_INCR(emfc, proto, igmp_frames_sentup,
192 mcast_data_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)
200 int32 res;
202 /* Dont forward the frame on to the port on which it
203 * was received.
205 if (ifp == ptr->ifp)
206 continue;
208 if (proto == IP_PROT_IGMP)
210 /* Dont forward IGMP frame if the port is not router port */
211 if (ptr->rtport_ref == 0)
212 continue;
214 else
216 /* Dont forward data frame if the port is neither router
217 * port nor uffp
219 if ((ptr->rtport_ref + ptr->uffp_ref) == 0)
220 continue;
223 if ((sdu_clone = PKTDUP(emfc->osh, sdu)) == NULL)
225 EMFC_PROT_STATS_INCR(emfc, proto, igmp_frames_dropped,
226 mcast_data_dropped);
227 OSL_UNLOCK(emfc->iflist_lock);
228 return (EMF_DROP);
231 EMF_RELOCK(emfc->iflist_lock);
232 res = emfc->wrapper.forward_fn(emfc->emfi, sdu_clone, dest_ip,
233 ptr->ifp, rt_port);
234 OSL_RELOCK(emfc->iflist_lock);
235 if (res != SUCCESS)
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,
240 mcast_data_dropped);
243 mcast_flooded++;
246 OSL_UNLOCK(emfc->iflist_lock);
248 if (mcast_flooded > 0)
250 EMFC_PROT_STATS_INCR(emfc, proto, igmp_frames_fwd,
251 mcast_data_flooded);
253 else
255 if (rt_port)
257 EMFC_PROT_STATS_INCR(emfc, proto, igmp_frames_dropped,
258 mcast_data_dropped);
262 PKTFREE(emfc->osh, sdu, FALSE);
264 return (EMF_TAKEN);
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
280 * the packet back.
281 * EMF_TAKEN - EMF has taken the ownership of the packet.
282 * EMF_DROP - Drop and free the packet.
284 uint32
285 emfc_input(emfc_info_t *emfc, void *sdu, void *ifp, uint8 *iph, bool rt_port)
287 uint32 dest_ip;
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");
301 return (EMF_NOP);
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");
308 return (EMF_NOP);
311 /* Check the protocol type of multicast frame */
312 if ((IPV4_PROT(iph) == IP_PROT_IGMP) && (emfc->snooper != NULL))
314 int32 action;
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);
329 switch (action)
331 case EMF_DROP:
332 EMF_INFO("Dropping the IGMP frame\n");
333 return (EMF_DROP);
335 case EMF_SENDUP:
336 emfc->wrapper.sendup_fn(emfc->emfi, sdu);
337 EMFC_STATS_INCR(emfc, igmp_frames_sentup);
338 return (EMF_TAKEN);
340 case EMF_FORWARD:
341 return (emfc_unreg_frame_handle(emfc, sdu, ifp,
342 IPV4_PROT(iph),
343 dest_ip, rt_port));
345 case EMF_FLOOD:
346 EMF_DEBUG("Returning the IGMP frame to bridge\n");
347 EMFC_STATS_INCR(emfc, igmp_frames_fwd);
348 break;
350 default:
351 EMF_ERROR("Unknown return value from IGMP Snooper\n");
352 EMFC_STATS_INCR(emfc, igmp_frames_fwd);
353 break;
356 return (EMF_NOP);
358 else
360 clist_head_t *ptr;
361 emfc_mgrp_t *mgrp;
362 emfc_mi_t *mi;
363 void *sdu_clone;
364 int32 res;
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
373 * the ports.
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");
378 return (EMF_NOP);
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.
391 if (mgrp == NULL)
393 OSL_UNLOCK(emfc->fdb_lock);
394 EMF_DEBUG("MFDB Group entry not found\n");
395 return (emfc_unreg_frame_handle(emfc, sdu, ifp,
396 IPV4_PROT(iph),
397 dest_ip, rt_port));
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.
405 if (!rt_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);
413 return (EMF_DROP);
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
431 * was received.
433 if (ifp == mi->mi_mhif->mhif_ifp)
434 continue;
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);
442 return (EMF_DROP);
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++,
451 mi->mi_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++,
468 mi->mi_data_fwd++;
470 else
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);
480 return (EMF_TAKEN);
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
493 static void
494 emfc_mfdb_init(emfc_info_t *emfc)
496 int32 i;
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;
511 return;
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
523 * otherwise.
525 static emfc_mi_t *
526 emfc_mfdb_mi_entry_find(emfc_info_t *emfc, emfc_mgrp_t *mgrp, void *ifp)
528 emfc_mi_t *mi;
529 clist_head_t *ptr;
531 ASSERT(mgrp);
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)
539 return (mi);
543 return (NULL);
547 * Description: This function does the MFDB lookup to locate a multicast
548 * group entry.
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.
556 static emfc_mgrp_t *
557 emfc_mfdb_group_find(emfc_info_t *emfc, uint32 mgrp_ip)
559 uint32 hash;
560 emfc_mgrp_t *mgrp;
561 clist_head_t *ptr;
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];
583 ptr = ptr->next)
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;
595 return (mgrp);
599 return (NULL);
603 * Add the entry if not present otherwise return the pointer to
604 * the entry.
606 emfc_mhif_t *
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)
615 return (ptr);
619 /* Add new entry */
620 mhif = MALLOC(emfc->osh, sizeof(emfc_mhif_t));
621 if (mhif == NULL)
623 EMF_ERROR("Failed to alloc mem size %d for mhif entry\n",
624 sizeof(emfc_mhif_t));
625 return (NULL);
628 mhif->mhif_ifp = ifp;
629 mhif->mhif_data_fwd = 0;
630 mhif->next = emfc->mhif_head;
631 emfc->mhif_head = mhif;
633 return (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
643 * is present.
645 * Return: Returns NULL is no interface entry is found. Otherwise
646 * returns pointer to the MFDB interface entry.
648 emfc_mi_t *
649 emfc_mfdb_membership_find(emfc_info_t *emfc, uint32 mgrp_ip, void *ifp)
651 emfc_mi_t *mi;
652 emfc_mgrp_t *mgrp;
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);
661 if (mgrp != NULL)
663 /* Find interface entry */
664 mi = emfc_mfdb_mi_entry_find(emfc, mgrp, ifp);
665 if (mi != NULL)
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);
670 return (mi);
674 OSL_UNLOCK(emfc->fdb_lock);
676 EMF_MFDB("Interface entry %x %p not found\n", mgrp_ip, ifp);
678 return (NULL);
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
685 * static MFDB entry.
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
694 int32
695 emfc_mfdb_membership_add(emfc_info_t *emfc, uint32 mgrp_ip, void *ifp)
697 uint32 hash;
698 emfc_mgrp_t *mgrp;
699 emfc_mi_t *mi;
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);
710 if (mgrp == NULL)
712 /* Allocate and initialize multicast group entry */
713 mgrp = MALLOC(emfc->osh, sizeof(emfc_mgrp_t));
714 if (mgrp == NULL)
716 EMF_ERROR("Failed to alloc mem size %d for group entry\n",
717 sizeof(emfc_mgrp_t));
718 OSL_UNLOCK(emfc->fdb_lock);
719 return (FAILURE);
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);
733 else
735 mi = emfc_mfdb_mi_entry_find(emfc, mgrp, ifp);
737 /* Update the ref count */
738 if (mi != NULL)
740 mi->mi_ref++;
741 OSL_UNLOCK(emfc->fdb_lock);
742 return (SUCCESS);
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));
750 if (mi == NULL)
752 EMF_ERROR("Failed to allocated memory %d for interface entry\n",
753 sizeof(emfc_mi_t));
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);
762 return (FAILURE);
765 /* Initialize the multicast interface list entry */
766 mi->mi_ref = 1;
767 mi->mi_mhif = emfc_mfdb_mhif_add(emfc, ifp);
768 mi->mi_data_fwd = 0;
770 /* Add the multicast interface entry */
771 clist_add_head(&mgrp->mi_head, &mi->mi_list);
773 OSL_UNLOCK(emfc->fdb_lock);
775 return (SUCCESS);
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
782 * group.
784 * Input: Same as above function.
786 * Return: SUCCESS or FAILURE
788 int32
789 emfc_mfdb_membership_del(emfc_info_t *emfc, uint32 mgrp_ip, void *ifp)
791 emfc_mi_t *mi;
792 emfc_mgrp_t *mgrp;
794 OSL_LOCK(emfc->fdb_lock);
796 /* Find group entry */
797 mgrp = emfc_mfdb_group_find(emfc, mgrp_ip);
799 if (mgrp == NULL)
801 OSL_UNLOCK(emfc->fdb_lock);
802 return (FAILURE);
805 /* Find interface entry */
806 mi = emfc_mfdb_mi_entry_find(emfc, mgrp, ifp);
808 if (mi == NULL)
810 OSL_UNLOCK(emfc->fdb_lock);
811 return (FAILURE);
814 EMF_MFDB("Deleting MFDB interface entry for interface %p\n", ifp);
816 /* Delete the interface entry when ref count reaches zero */
817 mi->mi_ref--;
818 if (mi->mi_ref != 0)
820 OSL_UNLOCK(emfc->fdb_lock);
821 return (SUCCESS);
823 else
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);
848 return (SUCCESS);
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
857 void
858 emfc_mfdb_clear(emfc_info_t *emfc)
860 uint32 i;
861 emfc_mgrp_t *mgrp;
862 emfc_mi_t *mi;
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);
881 tmp2 = ptr2->next;
882 EMF_MFDB("Deleting interface entry %p\n", mi);
883 clist_delete(ptr2);
884 MFREE(emfc->osh, mi, sizeof(emfc_mi_t));
887 tmp1 = ptr1->next;
889 /* Delete the group entry when there are no more interface
890 * entries for this group.
892 clist_delete(ptr1);
893 MFREE(emfc->osh, mgrp, sizeof(emfc_mgrp_t));
897 emfc->mgrp_cache_ip = 0;
899 OSL_UNLOCK(emfc->fdb_lock);
901 return;
905 * EMFC Interface List cleanup
907 static void
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;
915 while (ptr != NULL)
917 temp = ptr->next;
918 MFREE(emfc->osh, ptr, sizeof(emfc_iflist_t));
919 ptr = temp;
922 emfc->iflist_head = NULL;
924 OSL_UNLOCK(emfc->iflist_lock);
926 return;
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.
940 static void
941 emfc_cfg_emf_enable(emfc_info_t *emfc, emf_cfg_request_t *cfg)
943 bool emf_enable;
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;
953 break;
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");
963 break;
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");
976 break;
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);
986 else
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;
1006 break;
1008 default:
1009 cfg->status = EMFCFG_STATUS_OPER_UNKNOWN;
1010 cfg->size = sprintf(cfg->arg, "Unknown operation\n");
1011 break;
1014 return;
1018 * EMFL Packet Counters/Statistics
1020 int32
1021 emfc_stats_get(emfc_info_t *emfc, emf_stats_t *emfs, uint32 size)
1023 if (emfc == NULL)
1025 EMF_ERROR("Invalid EMFC handle passed\n");
1026 return (FAILURE);
1029 if (emfs == NULL)
1031 EMF_ERROR("Invalid buffer input\n");
1032 return (FAILURE);
1035 if (size < sizeof(emf_stats_t))
1037 EMF_ERROR("Insufficient buffer size %d\n", size);
1038 return (FAILURE);
1041 *emfs = emfc->stats;
1043 return (SUCCESS);
1047 * MFDB Listing Function
1049 int32
1050 emfc_mfdb_list(emfc_info_t *emfc, emf_cfg_mfdb_list_t *list, uint32 size)
1052 clist_head_t *ptr1, *ptr2;
1053 emfc_mi_t *mi;
1054 emfc_mgrp_t *mgrp;
1055 int32 i, index = 0;
1057 if (emfc == NULL)
1059 EMF_ERROR("Invalid EMFC handle passed\n");
1060 return (FAILURE);
1063 if (list == NULL)
1065 EMF_ERROR("Invalid buffer input\n");
1066 return (FAILURE);
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;
1084 index++;
1089 /* Update the total number of entries */
1090 list->num_entries = index;
1092 return (SUCCESS);
1096 * EMFC Interface List find
1098 static emfc_iflist_t *
1099 emfc_iflist_find(emfc_info_t *emfc, void *ifp, emfc_iflist_t **prev)
1101 emfc_iflist_t *ptr;
1103 OSL_LOCK(emfc->iflist_lock);
1105 *prev = NULL;
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);
1112 return (ptr);
1116 OSL_UNLOCK(emfc->iflist_lock);
1118 return (NULL);
1122 * EMFC Interface List add entry
1124 int32
1125 emfc_iflist_add(emfc_info_t *emfc, void *ifp)
1127 emfc_iflist_t *iflist, *prev;
1129 if (ifp == NULL)
1131 EMF_ERROR("Invalid interface identifier\n");
1132 return (FAILURE);
1135 if (emfc_iflist_find(emfc, ifp, &prev) != NULL)
1137 EMF_DEBUG("Adding duplicate interface entry\n");
1138 return (FAILURE);
1141 /* Allocate and initialize UFFP entry */
1142 iflist = MALLOC(emfc->osh, sizeof(emfc_iflist_t));
1143 if (iflist == NULL)
1145 EMF_ERROR("Failed to alloc mem size %d for interface entry\n",
1146 sizeof(emfc_iflist_t));
1147 return (FAILURE);
1150 iflist->ifp = ifp;
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);
1160 return (SUCCESS);
1164 * EMFC Interface List delete entry
1166 int32
1167 emfc_iflist_del(emfc_info_t *emfc, void *ifp)
1169 emfc_iflist_t *ptr, *prev;
1171 if (ifp == NULL)
1173 EMF_ERROR("Invalid interface identifier\n");
1174 return (FAILURE);
1177 if ((ptr = emfc_iflist_find(emfc, ifp, &prev)) == NULL)
1179 EMF_ERROR("UFFP entry not found\n");
1180 return (FAILURE);
1183 OSL_LOCK(emfc->iflist_lock);
1185 /* Delete the UFFP entry from the list */
1186 if (prev != NULL)
1187 prev->next = ptr->next;
1188 else
1189 emfc->iflist_head = ptr->next;
1191 OSL_UNLOCK(emfc->iflist_lock);
1193 MFREE(emfc->osh, ptr, sizeof(emfc_iflist_t));
1195 return (SUCCESS);
1199 * UFFP add entry
1201 static int32
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)
1211 iflist->uffp_ref++;
1212 OSL_UNLOCK(emfc->iflist_lock);
1214 return (SUCCESS);
1218 * UFFP delete entry
1220 static int32
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)
1226 return (FAILURE);
1228 /* Delete the interface entry when flags is zero */
1229 OSL_LOCK(emfc->iflist_lock);
1230 iflist->uffp_ref--;
1231 if ((iflist->uffp_ref == 0) && (iflist->rtport_ref == 0))
1232 emfc_iflist_del(emfc, ifp);
1233 OSL_UNLOCK(emfc->iflist_lock);
1235 return (SUCCESS);
1239 * UFFP Interface Listing
1241 static int32
1242 emfc_uffp_list(emfc_info_t *emfc, emf_cfg_uffp_list_t *list, uint32 size)
1244 int32 index = 0, bytes = 0;
1245 emfc_iflist_t *ptr;
1247 for (ptr = emfc->iflist_head; ptr != NULL; ptr = ptr->next)
1249 if (ptr->uffp_ref == 0)
1250 continue;
1252 bytes += sizeof(emf_cfg_uffp_t);
1253 if (bytes > size)
1254 return (FAILURE);
1256 strncpy(list->uffp_entry[index].if_name, DEV_IFNAME(ptr->ifp), 16);
1257 list->uffp_entry[index].if_name[15] = 0;
1258 index++;
1261 /* Update the total number of entries */
1262 list->num_entries = index;
1264 return (SUCCESS);
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
1272 * router port.
1274 * Input: emfc - EMFC Global Instance handle
1275 * ifp - Interface pointer
1277 * Return: SUCCESS/FAILURE
1279 int32
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);
1294 return (SUCCESS);
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
1307 int32
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");
1315 return (FAILURE);
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);
1325 return (SUCCESS);
1329 * RTPORT listing function
1331 static int32
1332 emfc_rtport_list(emfc_info_t *emfc, emf_cfg_rtport_list_t *list, uint32 size)
1334 int32 index = 0, bytes = 0;
1335 emfc_iflist_t *ptr;
1337 for (ptr = emfc->iflist_head; ptr != NULL; ptr = ptr->next)
1339 if (ptr->rtport_ref == 0)
1340 continue;
1342 bytes += sizeof(emf_cfg_rtport_t);
1343 if (bytes > size)
1344 return (FAILURE);
1346 strncpy(list->rtport_entry[index].if_name, DEV_IFNAME(ptr->ifp), 16);
1347 list->rtport_entry[index].if_name[15] = 0;
1348 index++;
1351 /* Update the total number of entries */
1352 list->num_entries = index;
1354 return (SUCCESS);
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.
1363 void
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);
1376 break;
1378 case EMFCFG_CMD_MFDB_ADD:
1379 mfdb = (emf_cfg_mfdb_t *)cfg->arg;
1380 cfg->size = 0;
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");
1388 break;
1391 cfg->status = EMFCFG_STATUS_SUCCESS;
1393 EMF_MFDB("MFDB entry %x %p added by user\n",
1394 mfdb->mgrp_ip, mfdb->if_ptr);
1395 break;
1397 case EMFCFG_CMD_MFDB_DEL:
1398 mfdb = (emf_cfg_mfdb_t *)cfg->arg;
1399 cfg->size = 0;
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");
1407 break;
1410 cfg->status = EMFCFG_STATUS_SUCCESS;
1412 EMF_MFDB("MFDB entry %x %p deleted by user\n",
1413 mfdb->mgrp_ip, mfdb->if_ptr);
1414 break;
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");
1422 break;
1425 cfg->status = EMFCFG_STATUS_SUCCESS;
1426 break;
1428 case EMFCFG_CMD_MFDB_CLEAR:
1429 emfc_mfdb_clear(emfc);
1430 cfg->status = EMFCFG_STATUS_SUCCESS;
1431 break;
1433 case EMFCFG_CMD_RTPORT_ADD:
1434 rtport = (emf_cfg_rtport_t *)cfg->arg;
1435 cfg->size = 0;
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");
1442 break;
1445 cfg->status = EMFCFG_STATUS_SUCCESS;
1446 break;
1448 case EMFCFG_CMD_RTPORT_DEL:
1449 rtport = (emf_cfg_rtport_t *)cfg->arg;
1450 cfg->size = 0;
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");
1457 break;
1460 cfg->status = EMFCFG_STATUS_SUCCESS;
1461 break;
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");
1469 break;
1472 cfg->status = EMFCFG_STATUS_SUCCESS;
1473 break;
1475 case EMFCFG_CMD_UFFP_ADD:
1476 uffp = (emf_cfg_uffp_t *)cfg->arg;
1477 cfg->size = 0;
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");
1484 break;
1487 cfg->status = EMFCFG_STATUS_SUCCESS;
1488 break;
1490 case EMFCFG_CMD_UFFP_DEL:
1491 uffp = (emf_cfg_uffp_t *)cfg->arg;
1492 cfg->size = 0;
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");
1499 break;
1502 cfg->status = EMFCFG_STATUS_SUCCESS;
1503 break;
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");
1511 break;
1514 cfg->status = EMFCFG_STATUS_SUCCESS;
1515 break;
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");
1523 break;
1526 cfg->status = EMFCFG_STATUS_SUCCESS;
1527 break;
1529 default:
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");
1533 break;
1536 return;
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
1552 emfc_info_t *
1553 emfc_init(int8 *inst_id, void *emfi, osl_t *osh, emfc_wrapper_t *wrapper)
1555 emfc_info_t *emfc;
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");
1563 return (NULL);
1566 /* Allocate memory */
1567 emfc = MALLOC(osh, sizeof(emfc_info_t));
1568 if (emfc == NULL)
1570 EMF_ERROR("Failed to allocated memory size %d for MFL\n",
1571 sizeof(emfc_info_t));
1572 return (NULL);
1575 EMF_DEBUG("Allocated memory for EMFC info\n");
1577 /* Initialize the EMF global data */
1578 bzero(emfc, sizeof(emfc_info_t));
1579 emfc->osh = osh;
1580 emfc->emfi = emfi;
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));
1596 return (NULL);
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));
1605 return (NULL);
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");
1625 return (emfc);
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
1635 void
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;
1654 while (ptr != NULL)
1656 temp = ptr->next;
1657 MFREE(emfc->osh, ptr, sizeof(emfc_mhif_t));
1658 ptr = temp;
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");
1674 return;
1678 * Description: This function is called from OS specific module init
1679 * routine. This allocates global resources required by the
1680 * common code.
1682 int32
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");
1691 return (FAILURE);
1694 return (SUCCESS);
1698 * Description: This function is called from OS specific module cleanup
1699 * routine. This frees all the global resources.
1701 void
1702 emfc_module_exit(void)
1704 OSL_LOCK_DESTROY(emfc_list_lock);
1705 return;