Broadcom SDK and wireless driver: another attempt to update to ver. 5.10.147.0
[tomato.git] / release / src-rt / emf / emf / emfc.c
blobf03f519190adff61bf3cdf181af21fa4bc2f17b8
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) 2009, 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,v 1.4 2010/02/17 23:36:15 Exp $
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 static CLIST_DECL_INIT(emfc_list_head);
38 static osl_lock_t emfc_list_lock;
40 static emfc_info_t *
41 emfc_instance_find(char *inst_id)
43 emfc_info_t *emfc;
44 clist_head_t *ptr;
46 if (inst_id == NULL)
48 EMF_ERROR("Invalid instance id string\n");
49 return (NULL);
52 OSL_LOCK(emfc_list_lock);
54 for (ptr = emfc_list_head.next; ptr != &emfc_list_head;
55 ptr = ptr->next)
57 emfc = clist_entry(ptr, emfc_info_t, emfc_list);
59 if (strcmp(inst_id, emfc->inst_id) == 0)
61 OSL_UNLOCK(emfc_list_lock);
62 return (emfc);
66 OSL_UNLOCK(emfc_list_lock);
68 return (NULL);
72 * Description: This function is called by the IGMP snooper layer to
73 * register snooper instance with EMFL.
75 * Input: inst_id - Instance identier used to associate EMF
76 * and IGMP snooper instances.
77 * emfc - EMFL Common code global instance handle
78 * snooper - Contains snooper specific parameters and
79 * event callback functions. These functions
80 * are called by EMFL on events like IGMP
81 * packet receive, EMF enable and disable.
82 * The snooper parameter needs to global or
83 * persistent.
85 * Return: SUCCESS or FAILURE
87 int32
88 emfc_igmp_snooper_register(int8 *inst_id, emfc_info_t **emfc, emfc_snooper_t *snooper)
90 /* Invalid input */
91 if (snooper == NULL)
93 EMF_ERROR("Snooper parameter should be non NULL\n");
94 return (FAILURE);
97 if (emfc == NULL)
99 EMF_ERROR("EMF handle should be non NULL\n");
100 return (FAILURE);
103 /* Validate the instance id */
104 if ((*emfc = emfc_instance_find(inst_id)) == NULL)
106 EMF_ERROR("EMF Instance doesn't exist\n");
107 return (FAILURE);
110 if (snooper->input_fn == NULL)
112 EMF_ERROR("Snooper input function should be non NULL\n");
113 return (FAILURE);
116 (*emfc)->snooper = snooper;
118 return (SUCCESS);
122 * Description: This function is called by the IGMP snooper layer
123 * to unregister snooper instance.
125 * Input: handle - Handle returned during registration.
126 * snooper - Contains snooper specific parameters and
128 void
129 emfc_igmp_snooper_unregister(emfc_info_t *emfc)
131 if (emfc == NULL)
133 EMF_ERROR("Unregistering using invalid handle\n");
134 return;
137 emfc->snooper = NULL;
139 return;
143 * Description: This function handles the unregistered frame forwarding.
144 * IGMP frames are forwarded on router ports. Data frames
145 * are flooded on to user configured UFFP.
147 * Input: emfc - EMFC Global instance data
148 * sdu - Pointer to packet buffer.
149 * ifp - Interface on which the packet arrived.
150 * dest_ip - Multicast destination IP address
151 * rt_port - TRUE when the packet is received from IP
152 * Stack otherwise FALSE.
154 * Return: EMF_TAKEN - EMF has taken the ownership of the packet.
155 * EMF_NOP - No processing needed by EMF, just return
156 * the packet back.
157 * EMF_DROP - Drop and free the packet.
159 static uint32
160 emfc_unreg_frame_handle(emfc_info_t *emfc, void *sdu, void *ifp, uint8 proto,
161 uint32 dest_ip, bool rt_port)
163 emfc_iflist_t *ptr;
164 void *sdu_clone;
165 uint32 mcast_flooded = 0;
167 /* Forward the frame on to router port */
168 if (!rt_port)
170 EMF_DEBUG("Sending frame on to router port\n");
172 if ((sdu_clone = PKTDUP(emfc->osh, sdu)) == NULL)
174 EMFC_PROT_STATS_INCR(emfc, proto, igmp_frames_dropped,
175 mcast_data_dropped);
176 return (EMF_DROP);
179 emfc->wrapper.sendup_fn(emfc->emfi, sdu_clone);
181 EMFC_PROT_STATS_INCR(emfc, proto, igmp_frames_sentup,
182 mcast_data_sentup);
185 OSL_LOCK(emfc->iflist_lock);
187 /* Flood the frame on to user specified ports */
188 for (ptr = emfc->iflist_head; ptr != NULL; ptr = ptr->next)
190 /* Dont forward the frame on to the port on which it
191 * was received.
193 if (ifp == ptr->ifp)
194 continue;
196 if (proto == IP_PROT_IGMP)
198 /* Dont forward IGMP frame if the port is not router port */
199 if (ptr->rtport_ref == 0)
200 continue;
202 else
204 /* Dont forward data frame if the port is neither router
205 * port nor uffp
207 if ((ptr->rtport_ref + ptr->uffp_ref) == 0)
208 continue;
211 if ((sdu_clone = PKTDUP(emfc->osh, sdu)) == NULL)
213 EMFC_PROT_STATS_INCR(emfc, proto, igmp_frames_dropped,
214 mcast_data_dropped);
215 OSL_UNLOCK(emfc->iflist_lock);
216 return (EMF_DROP);
219 if (emfc->wrapper.forward_fn(emfc->emfi, sdu_clone, dest_ip,
220 ptr->ifp, rt_port) != SUCCESS)
222 EMF_INFO("Unable to flood the unreg frame on to %s\n",
223 DEV_IFNAME(ptr->ifp));
224 EMFC_PROT_STATS_INCR(emfc, proto, igmp_frames_dropped,
225 mcast_data_dropped);
228 mcast_flooded++;
231 OSL_UNLOCK(emfc->iflist_lock);
233 if (mcast_flooded > 0)
235 EMFC_PROT_STATS_INCR(emfc, proto, igmp_frames_fwd,
236 mcast_data_flooded);
238 else
240 if (rt_port)
242 EMFC_PROT_STATS_INCR(emfc, proto, igmp_frames_dropped,
243 mcast_data_dropped);
247 PKTFREE(emfc->osh, sdu, FALSE);
249 return (EMF_TAKEN);
253 * Description: This function is called from the registered OS hook
254 * points once for every frame. This function does the
255 * MFDB lookup, packet cloning and frame forwarding.
257 * Input: emfc - EMFC Global instance data
258 * sdu - Pointer to packet buffer.
259 * ifp - Interface on which the packet arrived.
260 * iph - Pointer to start of IP header.
261 * rt_port - TRUE when the packet is received from IP
262 * Stack otherwise FALSE.
264 * Return: EMF_NOP - No processing needed by EMF, just return
265 * the packet back.
266 * EMF_TAKEN - EMF has taken the ownership of the packet.
267 * EMF_DROP - Drop and free the packet.
269 uint32
270 emfc_input(emfc_info_t *emfc, void *sdu, void *ifp, uint8 *iph, bool rt_port)
272 uint32 dest_ip;
274 EMF_DEBUG("Received frame with dest ip %d.%d.%d.%d\n",
275 iph[IPV4_DEST_IP_OFFSET], iph[IPV4_DEST_IP_OFFSET + 1],
276 iph[IPV4_DEST_IP_OFFSET + 2], iph[IPV4_DEST_IP_OFFSET + 3]);
278 dest_ip = ntoh32(*((uint32 *)(iph + IPV4_DEST_IP_OFFSET)));
280 /* No processing is required if the received frame is unicast or
281 * broadcast, when EMF is disabled. Send the frame back to bridge.
283 if ((!IP_ISMULTI(dest_ip)) || (!emfc->emf_enable))
285 EMF_DEBUG("Unicast frame recevied/EMF disabled\n");
286 return (EMF_NOP);
289 /* Non-IPv4 multicast packets are not handled */
290 if (IP_VER(iph) != IP_VER_4)
292 EMF_INFO("Non-IPv4 multicast packets will be flooded\n");
293 return (EMF_NOP);
296 /* Check the protocol type of multicast frame */
297 if ((IPV4_PROT(iph) == IP_PROT_IGMP) && (emfc->snooper != NULL))
299 int32 action;
301 EMF_DEBUG("Received IGMP frame type %d\n", *(iph + IPV4_HLEN(iph)));
303 EMFC_STATS_INCR(emfc, igmp_frames);
305 /* IGMP packet received from LAN or IP Stack. Call the IGMP
306 * Snooping function. Based on the IGMP packet type it may
307 * add/delete MFDB entry. Also the function return value
308 * tells whether to drop, forward, or flood the frame.
310 ASSERT(emfc->snooper->input_fn);
311 action = emfc->snooper->input_fn(emfc->snooper, ifp, iph,
312 iph + IPV4_HLEN(iph), rt_port);
314 switch (action)
316 case EMF_DROP:
317 EMF_INFO("Dropping the IGMP frame\n");
318 return (EMF_DROP);
320 case EMF_SENDUP:
321 emfc->wrapper.sendup_fn(emfc->emfi, sdu);
322 EMFC_STATS_INCR(emfc, igmp_frames_sentup);
323 return (EMF_TAKEN);
325 case EMF_FORWARD:
326 return (emfc_unreg_frame_handle(emfc, sdu, ifp,
327 IPV4_PROT(iph),
328 dest_ip, rt_port));
330 case EMF_FLOOD:
331 EMF_DEBUG("Returning the IGMP frame to bridge\n");
332 EMFC_STATS_INCR(emfc, igmp_frames_fwd);
333 break;
335 default:
336 EMF_ERROR("Unknown return value from IGMP Snooper\n");
337 EMFC_STATS_INCR(emfc, igmp_frames_fwd);
338 break;
341 return (EMF_NOP);
343 else
345 clist_head_t *ptr;
346 emfc_mgrp_t *mgrp;
347 emfc_mi_t *mi;
348 void *sdu_clone;
350 EMF_DEBUG("Received frame with proto %d\n", IPV4_PROT(iph));
352 EMFC_STATS_INCR(emfc, mcast_data_frames);
354 /* Packets with destination IP address in the range 224.0.0.x
355 * must be forwarded on all ports. Similarly UPnP specific
356 * protocol traffic such as SSDP must be forwarded on to all
357 * the ports.
359 if (MCAST_ADDR_LINKLOCAL(dest_ip) || MCAST_ADDR_UPNP_SSDP(dest_ip))
361 EMF_DEBUG("Flooding the frames with link-local/ssdp address\n");
362 return (EMF_NOP);
365 OSL_LOCK(emfc->fdb_lock);
367 /* Do the MFDB lookup to determine the destination port(s)
368 * to forward the frame.
370 mgrp = emfc_mfdb_group_find(emfc, dest_ip);
372 /* If no matching MFDB entry is found send the frame back to
373 * bridge module so that it floods on to all the ports.
375 if (mgrp == NULL)
377 OSL_UNLOCK(emfc->fdb_lock);
378 EMF_DEBUG("MFDB Group entry not found\n");
379 return (emfc_unreg_frame_handle(emfc, sdu, ifp,
380 IPV4_PROT(iph),
381 dest_ip, rt_port));
384 ASSERT(!clist_empty(&mgrp->mi_head));
386 /* If the data frame is received from one of the bridge
387 * ports then a copy has to be sent up to the router port.
389 if (!rt_port)
391 EMF_DEBUG("Sending to router port\n");
393 if ((sdu_clone = PKTDUP(emfc->osh, sdu)) == NULL)
395 OSL_UNLOCK(emfc->fdb_lock);
396 EMFC_STATS_INCR(emfc, mcast_data_dropped);
397 return (EMF_DROP);
400 emfc->wrapper.sendup_fn(emfc->emfi, sdu_clone);
401 EMFC_STATS_INCR(emfc, mcast_data_sentup);
404 /* Data frame received from LAN or IP Stack (WAN). Clone
405 * the buffer and send on all but the last interface.
407 for (ptr = mgrp->mi_head.next;
408 ptr != mgrp->mi_head.prev; ptr = ptr->next)
410 mi = clist_entry(ptr, emfc_mi_t, mi_list);
412 /* Dont forward the frame on to the port on which it
413 * was received.
415 if (ifp == mi->mi_mhif->mhif_ifp)
416 continue;
418 EMF_DEBUG("Cloning the buffer for forwarding\n");
420 if ((sdu_clone = PKTDUP(emfc->osh, sdu)) == NULL)
422 OSL_UNLOCK(emfc->fdb_lock);
423 EMFC_STATS_INCR(emfc, mcast_data_dropped);
424 return (EMF_DROP);
427 emfc->wrapper.forward_fn(emfc->emfi, sdu_clone,
428 dest_ip, mi->mi_mhif->mhif_ifp, rt_port) ?
429 EMFC_STATS_INCR(emfc, mcast_data_dropped) :
430 mi->mi_mhif->mhif_data_fwd++,
431 mi->mi_data_fwd++;
434 /* Send the last frame without cloning */
435 mi = clist_entry(ptr, emfc_mi_t, mi_list);
437 /* Dont forward the frame on to the port on which it was received */
438 if (ifp != mi->mi_mhif->mhif_ifp)
440 EMF_DEBUG("Sending the original packet buffer\n");
442 emfc->wrapper.forward_fn(emfc->emfi, sdu, dest_ip,
443 mi->mi_mhif->mhif_ifp, rt_port) ?
444 EMFC_STATS_INCR(emfc, mcast_data_dropped) :
445 mi->mi_mhif->mhif_data_fwd++,
446 mi->mi_data_fwd++;
448 else
450 EMF_DEBUG("Freeing the original packet buffer\n");
451 PKTFREE(emfc->osh, sdu, FALSE);
454 EMFC_STATS_INCR(emfc, mcast_data_fwd);
456 OSL_UNLOCK(emfc->fdb_lock);
458 return (EMF_TAKEN);
463 * Description: This function initializes the MFDB. MFDB group
464 * entries are organized as a hash table with chaining
465 * for collision resolution. Each MFDB group entry
466 * points to the chain of MFDB interface entries that are
467 * members of the group.
469 * Input: emfc - EMFL Common code global data handle
471 static void
472 emfc_mfdb_init(emfc_info_t *emfc)
474 int32 i;
476 /* Initialize the multicast forwarding database */
477 for (i = 0; i < MFDB_HASHT_SIZE; i++)
479 clist_init_head(&emfc->mgrp_fdb[i]);
482 /* Initialize the multicast interface list. This list contains
483 * all the interfaces that have multicast group members. Entries in
484 * this list are never expired/deleted. Each entry maintains stats
485 * specific to the interface.
487 emfc->mhif_head = NULL;
489 return;
493 * Description: This function does the MFDB lookup to locate interface
494 * entry of the specified group.
496 * Input: emfc - EMFL Common code global data handle
497 * mgrp - Pointer to multicast group entry of MFDB
498 * ifp - Interface pointer to locate.
500 * Return: Returns pointer to the MFDB interface entry, NULL
501 * otherwise.
503 static emfc_mi_t *
504 emfc_mfdb_mi_entry_find(emfc_info_t *emfc, emfc_mgrp_t *mgrp, void *ifp)
506 emfc_mi_t *mi;
507 clist_head_t *ptr;
509 ASSERT(mgrp);
511 for (ptr = mgrp->mi_head.next;
512 ptr != &mgrp->mi_head; ptr = ptr->next)
514 mi = clist_entry(ptr, emfc_mi_t, mi_list);
515 if (ifp == mi->mi_mhif->mhif_ifp)
517 return (mi);
521 return (NULL);
525 * Description: This function does the MFDB lookup to locate a multicast
526 * group entry.
528 * Input: emfc - EMFL Common code global data handle
529 * mgrp_ip - Multicast group address of the entry.
531 * Return: Returns NULL is no group entry is found. Otherwise
532 * returns pointer to the MFDB group entry.
534 static emfc_mgrp_t *
535 emfc_mfdb_group_find(emfc_info_t *emfc, uint32 mgrp_ip)
537 uint32 hash;
538 emfc_mgrp_t *mgrp;
539 clist_head_t *ptr;
541 ASSERT(IP_ISMULTI(mgrp_ip));
543 /* Do the cache lookup first. Since the multicast video traffic
544 * is bursty in nature there is a good chance that the cache
545 * hit ratio will be good. If during the testing we find that
546 * the hit ratio is not as good then this single entry cache
547 * mechanism will be removed.
549 if (mgrp_ip == emfc->mgrp_cache_ip)
551 EMFC_STATS_INCR(emfc, mfdb_cache_hits);
552 return (emfc->mgrp_cache);
555 EMFC_STATS_INCR(emfc, mfdb_cache_misses);
557 hash = MFDB_MGRP_HASH(mgrp_ip);
559 for (ptr = emfc->mgrp_fdb[hash].next;
560 ptr != &emfc->mgrp_fdb[hash];
561 ptr = ptr->next)
563 mgrp = clist_entry(ptr, emfc_mgrp_t, mgrp_hlist);
565 /* Compare group address */
566 if (mgrp_ip == mgrp->mgrp_ip)
568 EMF_MFDB("Multicast Group entry %d.%d.%d.%d found\n",
569 (mgrp_ip >> 24), ((mgrp_ip >> 16) & 0xff),
570 ((mgrp_ip >> 8) & 0xff), (mgrp_ip & 0xff));
571 emfc->mgrp_cache = mgrp;
572 emfc->mgrp_cache_ip = mgrp_ip;
573 return (mgrp);
577 return (NULL);
581 * Add the entry if not present otherwise return the pointer to
582 * the entry.
584 emfc_mhif_t *
585 emfc_mfdb_mhif_add(emfc_info_t *emfc, void *ifp)
587 emfc_mhif_t *ptr, *mhif;
589 OSL_LOCK(emfc->fdb_lock);
591 for (ptr = emfc->mhif_head; ptr != NULL; ptr = ptr->next)
593 if (ptr->mhif_ifp == ifp)
595 OSL_UNLOCK(emfc->fdb_lock);
596 return (ptr);
600 /* Add new entry */
601 mhif = MALLOC(emfc->osh, sizeof(emfc_mgrp_t));
602 if (mhif == NULL)
604 OSL_UNLOCK(emfc->fdb_lock);
605 EMF_ERROR("Failed to alloc mem size %d for mhif entry\n",
606 sizeof(emfc_mhif_t));
607 return (NULL);
610 mhif->mhif_ifp = ifp;
611 mhif->mhif_data_fwd = 0;
612 mhif->next = emfc->mhif_head;
613 emfc->mhif_head = mhif;
615 OSL_UNLOCK(emfc->fdb_lock);
617 return (mhif);
621 * Description: This function does the MFDB lookup to locate a interface
622 * entry of the specified multicast group.
624 * Input: emfc - EMFL Common code global data handle
625 * mgrp_ip - Multicast group IP address of the entry.
626 * ifp - Pointer to the interface on which the member
627 * is present.
629 * Return: Returns NULL is no interface entry is found. Otherwise
630 * returns pointer to the MFDB interface entry.
632 emfc_mi_t *
633 emfc_mfdb_membership_find(emfc_info_t *emfc, uint32 mgrp_ip, void *ifp)
635 emfc_mi_t *mi;
636 emfc_mgrp_t *mgrp;
638 ASSERT(IP_ISMULTI(mgrp_ip));
640 OSL_LOCK(emfc->fdb_lock);
642 /* Find group entry */
643 mgrp = emfc_mfdb_group_find(emfc, mgrp_ip);
645 if (mgrp != NULL)
647 /* Find interface entry */
648 mi = emfc_mfdb_mi_entry_find(emfc, mgrp, ifp);
649 if (mi != NULL)
651 EMF_MFDB("Interface entry %d.%d.%d.%d:%p found\n",
652 (mgrp_ip >> 24), ((mgrp_ip >> 16) & 0xff),
653 ((mgrp_ip >> 8) & 0xff), (mgrp_ip & 0xff), ifp);
654 return (mi);
658 OSL_UNLOCK(emfc->fdb_lock);
660 EMF_MFDB("Interface entry %x %p not found\n", mgrp_ip, ifp);
662 return (NULL);
666 * Description: This function is called by IGMP Snooper when it wants
667 * to add MFDB entry or refresh the entry. This function
668 * is also called by the management application to add a
669 * static MFDB entry.
671 * If the MFDB entry is not present, it allocates group
672 * entry, interface entry and links them together.
674 * Input: Same as above function.
676 * Return: SUCCESS or FAILURE
678 int32
679 emfc_mfdb_membership_add(emfc_info_t *emfc, uint32 mgrp_ip, void *ifp)
681 uint32 hash;
682 emfc_mgrp_t *mgrp;
683 emfc_mi_t *mi;
685 ASSERT(IP_ISMULTI(mgrp_ip));
687 OSL_LOCK(emfc->fdb_lock);
689 /* If the group entry doesn't exist, add a new entry and update
690 * the member/interface information.
692 mgrp = emfc_mfdb_group_find(emfc, mgrp_ip);
694 if (mgrp == NULL)
696 /* Allocate and initialize multicast group entry */
697 mgrp = MALLOC(emfc->osh, sizeof(emfc_mgrp_t));
698 if (mgrp == NULL)
700 EMF_ERROR("Failed to alloc mem size %d for group entry\n",
701 sizeof(emfc_mgrp_t));
702 OSL_UNLOCK(emfc->fdb_lock);
703 return (FAILURE);
706 mgrp->mgrp_ip = mgrp_ip;
707 clist_init_head(&mgrp->mi_head);
709 EMF_MFDB("Adding group entry %d.%d.%d.%d\n",
710 (mgrp_ip >> 24), ((mgrp_ip >> 16) & 0xff),
711 ((mgrp_ip >> 8) & 0xff), (mgrp_ip & 0xff));
713 /* Add the group entry to hash table */
714 hash = MFDB_MGRP_HASH(mgrp_ip);
715 clist_add_head(&emfc->mgrp_fdb[hash], &mgrp->mgrp_hlist);
717 else
719 mi = emfc_mfdb_mi_entry_find(emfc, mgrp, ifp);
721 /* Update the ref count */
722 if (mi != NULL)
724 mi->mi_ref++;
725 OSL_UNLOCK(emfc->fdb_lock);
726 return (SUCCESS);
730 EMF_MFDB("Adding interface entry for interface %p\n", ifp);
732 /* Allocate and initialize multicast interface entry */
733 mi = MALLOC(emfc->osh, sizeof(emfc_mi_t));
734 if (mi == NULL)
736 EMF_ERROR("Failed to allocated memory %d for interface entry\n",
737 sizeof(emfc_mi_t));
738 if (clist_empty(&mgrp->mi_head))
740 clist_delete(&mgrp->mgrp_hlist);
741 emfc->mgrp_cache_ip = ((emfc->mgrp_cache == mgrp) ?
742 0 : emfc->mgrp_cache_ip);
743 MFREE(emfc->osh, mgrp, sizeof(emfc_mgrp_t));
745 OSL_UNLOCK(emfc->fdb_lock);
746 return (FAILURE);
749 /* Initialize the multicast interface list entry */
750 mi->mi_ref = 1;
751 mi->mi_mhif = emfc_mfdb_mhif_add(emfc, ifp);
752 mi->mi_data_fwd = 0;
754 /* Add the multicast interface entry */
755 clist_add_head(&mgrp->mi_head, &mi->mi_list);
757 OSL_UNLOCK(emfc->fdb_lock);
759 return (SUCCESS);
763 * Description: This function is called by the IGMP snooper layer
764 * to delete the MFDB entry. It deletes the group
765 * entry also if the interface entry is last in the
766 * group.
768 * Input: Same as above function.
770 * Return: SUCCESS or FAILURE
772 int32
773 emfc_mfdb_membership_del(emfc_info_t *emfc, uint32 mgrp_ip, void *ifp)
775 emfc_mi_t *mi;
776 emfc_mgrp_t *mgrp;
778 OSL_LOCK(emfc->fdb_lock);
780 /* Find group entry */
781 mgrp = emfc_mfdb_group_find(emfc, mgrp_ip);
783 if (mgrp == NULL)
785 OSL_UNLOCK(emfc->fdb_lock);
786 return (FAILURE);
789 /* Find interface entry */
790 mi = emfc_mfdb_mi_entry_find(emfc, mgrp, ifp);
792 if (mi == NULL)
794 OSL_UNLOCK(emfc->fdb_lock);
795 return (FAILURE);
798 EMF_MFDB("Deleting MFDB interface entry for interface %p\n", ifp);
800 /* Delete the interface entry when ref count reaches zero */
801 mi->mi_ref--;
802 if (mi->mi_ref != 0)
804 OSL_UNLOCK(emfc->fdb_lock);
805 return (SUCCESS);
807 else
809 EMF_MFDB("Deleting interface entry %p\n", mi->mi_mhif->mhif_ifp);
810 clist_delete(&mi->mi_list);
813 /* If the member being deleted is last node in the interface list,
814 * delete the group entry also.
816 if (clist_empty(&mgrp->mi_head))
818 EMF_MFDB("Deleting group entry of %d.%d.%d.%d too\n",
819 (mgrp_ip >> 24), ((mgrp_ip >> 16) & 0xff),
820 ((mgrp_ip >> 8) & 0xff), (mgrp_ip & 0xff));
822 clist_delete(&mgrp->mgrp_hlist);
823 emfc->mgrp_cache_ip = ((emfc->mgrp_cache == mgrp) ?
824 0 : emfc->mgrp_cache_ip);
825 MFREE(emfc->osh, mgrp, sizeof(emfc_mgrp_t));
828 MFREE(emfc->osh, mi, sizeof(emfc_mi_t));
830 OSL_UNLOCK(emfc->fdb_lock);
832 return (SUCCESS);
836 * Description: This function clears the group interval timers and
837 * deletes the group and interface entries of the MFDB.
839 * Input: emfc - EMFL Common code global data handle
841 void
842 emfc_mfdb_clear(emfc_info_t *emfc)
844 uint32 i;
845 emfc_mgrp_t *mgrp;
846 emfc_mi_t *mi;
847 clist_head_t *ptr1, *ptr2, *tmp1, *tmp2;
849 OSL_LOCK(emfc->fdb_lock);
851 /* Delete all the group entries */
852 for (i = 0; i < MFDB_HASHT_SIZE; i++)
854 for (ptr1 = emfc->mgrp_fdb[i].next;
855 ptr1 != &emfc->mgrp_fdb[i]; ptr1 = tmp1)
857 mgrp = clist_entry(ptr1, emfc_mgrp_t, mgrp_hlist);
859 /* Delete all interface entries */
860 for (ptr2 = mgrp->mi_head.next;
861 ptr2 != &mgrp->mi_head; ptr2 = tmp2)
863 mi = clist_entry(ptr2, emfc_mi_t, mi_list);
865 tmp2 = ptr2->next;
866 EMF_MFDB("Deleting interface entry %p\n", mi);
867 clist_delete(ptr2);
868 MFREE(emfc->osh, mi, sizeof(emfc_mi_t));
871 tmp1 = ptr1->next;
873 /* Delete the group entry when there are no more interface
874 * entries for this group.
876 clist_delete(ptr1);
877 MFREE(emfc->osh, mgrp, sizeof(emfc_mgrp_t));
881 emfc->mgrp_cache_ip = 0;
883 OSL_UNLOCK(emfc->fdb_lock);
885 return;
889 * EMFC Interface List cleanup
891 static void
892 emfc_iflist_clear(emfc_info_t *emfc)
894 emfc_iflist_t *ptr, *temp;
896 OSL_LOCK(emfc->iflist_lock);
898 ptr = emfc->iflist_head;
899 while (ptr != NULL)
901 temp = ptr->next;
902 MFREE(emfc->osh, ptr, sizeof(emfc_iflist_t));
903 ptr = temp;
906 emfc->iflist_head = NULL;
908 OSL_UNLOCK(emfc->iflist_lock);
910 return;
914 * Description: This function is called to enable/disable the efficient
915 * multicast forwarding feature. When the config operation
916 * cannot be completed respective status is returned.
918 * Input: emfc - EMFL Common code global data handle
920 * Input/Output: cfg - Pointer to configuration request data. It contains
921 * the command id, operation type, corresponding
922 * arguments and output status.
924 static void
925 emfc_cfg_emf_enable(emfc_info_t *emfc, emf_cfg_request_t *cfg)
927 bool emf_enable;
929 EMF_DEBUG("Operation type: %d\n", cfg->oper_type);
931 switch (cfg->oper_type)
933 case EMFCFG_OPER_TYPE_GET:
934 *(bool *)cfg->arg = emfc->emf_enable;
935 cfg->size = sizeof(bool);
936 cfg->status = EMFCFG_STATUS_SUCCESS;
937 break;
939 case EMFCFG_OPER_TYPE_SET:
940 /* Enable or disable EMF */
941 emf_enable = (*(bool *)cfg->arg ? TRUE : FALSE);
942 if (emfc->emf_enable == emf_enable)
944 cfg->status = EMFCFG_STATUS_FAILURE;
945 cfg->size = sprintf(cfg->arg,
946 "Duplicate configuration request\n");
947 break;
950 emfc->emf_enable = emf_enable;
952 if (emfc->emf_enable)
954 /* Register the hooks to start receiving multicast frames */
955 if (emfc->wrapper.hooks_register_fn(emfc->emfi) != SUCCESS)
957 cfg->status = EMFCFG_STATUS_FAILURE;
958 cfg->size = sprintf(cfg->arg,
959 "Duplicate hooks registration\n");
960 break;
963 /* Call the registered EMF enable entry point function */
964 if (emfc->snooper && emfc->snooper->emf_enable_fn != NULL)
966 EMF_DEBUG("Calling the EMF enable function\n");
967 emfc->snooper->emf_enable_fn(emfc->snooper);
970 else
972 /* Call the registered EMF disable entry point function */
973 if (emfc->snooper && emfc->snooper->emf_disable_fn != NULL)
975 EMF_DEBUG("Calling the EMF disable function\n");
976 emfc->snooper->emf_disable_fn(emfc->snooper);
979 /* Unregister the packet hooks first */
980 emfc->wrapper.hooks_unregister_fn(emfc->emfi);
982 /* Cleanup the MFDB entries */
983 emfc_mfdb_clear(emfc);
985 /* Cleanup the UFFP entries */
986 emfc_iflist_clear(emfc);
989 cfg->status = EMFCFG_STATUS_SUCCESS;
990 break;
992 default:
993 cfg->status = EMFCFG_STATUS_OPER_UNKNOWN;
994 cfg->size = sprintf(cfg->arg, "Unknown operation\n");
995 break;
998 return;
1002 * EMFL Packet Counters/Statistics
1004 int32
1005 emfc_stats_get(emfc_info_t *emfc, emf_stats_t *emfs, uint32 size)
1007 if (emfc == NULL)
1009 EMF_ERROR("Invalid EMFC handle passed\n");
1010 return (FAILURE);
1013 if (emfs == NULL)
1015 EMF_ERROR("Invalid buffer input\n");
1016 return (FAILURE);
1019 if (size < sizeof(emf_stats_t))
1021 EMF_ERROR("Insufficient buffer size %d\n", size);
1022 return (FAILURE);
1025 *emfs = emfc->stats;
1027 return (SUCCESS);
1031 * MFDB Listing Function
1033 int32
1034 emfc_mfdb_list(emfc_info_t *emfc, emf_cfg_mfdb_list_t *list, uint32 size)
1036 clist_head_t *ptr1, *ptr2;
1037 emfc_mi_t *mi;
1038 emfc_mgrp_t *mgrp;
1039 int32 i, index = 0;
1041 if (emfc == NULL)
1043 EMF_ERROR("Invalid EMFC handle passed\n");
1044 return (FAILURE);
1047 if (list == NULL)
1049 EMF_ERROR("Invalid buffer input\n");
1050 return (FAILURE);
1053 for (i = 0; i < MFDB_HASHT_SIZE; i++)
1055 for (ptr1 = emfc->mgrp_fdb[i].next;
1056 ptr1 != &emfc->mgrp_fdb[i]; ptr1 = ptr1->next)
1058 mgrp = clist_entry(ptr1, emfc_mgrp_t, mgrp_hlist);
1059 for (ptr2 = mgrp->mi_head.next;
1060 ptr2 != &mgrp->mi_head; ptr2 = ptr2->next)
1062 mi = clist_entry(ptr2, emfc_mi_t, mi_list);
1064 list->mfdb_entry[index].mgrp_ip = mgrp->mgrp_ip;
1065 strncpy(list->mfdb_entry[index].if_name,
1066 DEV_IFNAME(mi->mi_mhif->mhif_ifp), 16);
1067 list->mfdb_entry[index].pkts_fwd = mi->mi_data_fwd;
1068 index++;
1073 /* Update the total number of entries */
1074 list->num_entries = index;
1076 return (SUCCESS);
1080 * EMFC Interface List find
1082 static emfc_iflist_t *
1083 emfc_iflist_find(emfc_info_t *emfc, void *ifp, emfc_iflist_t **prev)
1085 emfc_iflist_t *ptr;
1087 OSL_LOCK(emfc->iflist_lock);
1089 *prev = NULL;
1090 for (ptr = emfc->iflist_head; ptr != NULL;
1091 *prev = ptr, ptr = ptr->next)
1093 if (ptr->ifp == ifp)
1095 OSL_UNLOCK(emfc->iflist_lock);
1096 return (ptr);
1100 OSL_UNLOCK(emfc->iflist_lock);
1102 return (NULL);
1106 * EMFC Interface List add entry
1108 int32
1109 emfc_iflist_add(emfc_info_t *emfc, void *ifp)
1111 emfc_iflist_t *iflist, *prev;
1113 if (ifp == NULL)
1115 EMF_ERROR("Invalid interface identifier\n");
1116 return (FAILURE);
1119 if (emfc_iflist_find(emfc, ifp, &prev) != NULL)
1121 EMF_DEBUG("Adding duplicate interface entry\n");
1122 return (FAILURE);
1125 /* Allocate and initialize UFFP entry */
1126 iflist = MALLOC(emfc->osh, sizeof(emfc_iflist_t));
1127 if (iflist == NULL)
1129 EMF_ERROR("Failed to alloc mem size %d for interface entry\n",
1130 sizeof(emfc_iflist_t));
1131 return (FAILURE);
1134 iflist->ifp = ifp;
1135 iflist->uffp_ref = 0;
1136 iflist->rtport_ref = 0;
1138 /* Add the UFFP entry to the list */
1139 OSL_LOCK(emfc->iflist_lock);
1140 iflist->next = emfc->iflist_head;
1141 emfc->iflist_head = iflist;
1142 OSL_UNLOCK(emfc->iflist_lock);
1144 return (SUCCESS);
1148 * EMFC Interface List delete entry
1150 int32
1151 emfc_iflist_del(emfc_info_t *emfc, void *ifp)
1153 emfc_iflist_t *ptr, *prev;
1155 if (ifp == NULL)
1157 EMF_ERROR("Invalid interface identifier\n");
1158 return (FAILURE);
1161 if ((ptr = emfc_iflist_find(emfc, ifp, &prev)) == NULL)
1163 EMF_ERROR("UFFP entry not found\n");
1164 return (FAILURE);
1167 OSL_LOCK(emfc->iflist_lock);
1169 /* Delete the UFFP entry from the list */
1170 if (prev != NULL)
1171 prev->next = ptr->next;
1172 else
1173 emfc->iflist_head = ptr->next;
1175 OSL_UNLOCK(emfc->iflist_lock);
1177 MFREE(emfc->osh, ptr, sizeof(emfc_iflist_t));
1179 return (SUCCESS);
1183 * UFFP add entry
1185 static int32
1186 emfc_uffp_add(emfc_info_t *emfc, void *ifp)
1188 emfc_iflist_t *iflist, *prev;
1190 /* Add the interface entry if not present already */
1191 emfc_iflist_add(emfc, ifp);
1193 OSL_LOCK(emfc->iflist_lock);
1194 if ((iflist = emfc_iflist_find(emfc, ifp, &prev)) != NULL)
1195 iflist->uffp_ref++;
1196 OSL_UNLOCK(emfc->iflist_lock);
1198 return (SUCCESS);
1202 * UFFP delete entry
1204 static int32
1205 emfc_uffp_del(emfc_info_t *emfc, void *ifp)
1207 emfc_iflist_t *iflist, *prev;
1209 if ((iflist = emfc_iflist_find(emfc, ifp, &prev)) == NULL)
1210 return (FAILURE);
1212 /* Delete the interface entry when flags is zero */
1213 OSL_LOCK(emfc->iflist_lock);
1214 iflist->uffp_ref--;
1215 if ((iflist->uffp_ref == 0) && (iflist->rtport_ref == 0))
1216 emfc_iflist_del(emfc, ifp);
1217 OSL_UNLOCK(emfc->iflist_lock);
1219 return (SUCCESS);
1223 * UFFP Interface Listing
1225 static int32
1226 emfc_uffp_list(emfc_info_t *emfc, emf_cfg_uffp_list_t *list, uint32 size)
1228 int32 index = 0, bytes = 0;
1229 emfc_iflist_t *ptr;
1231 for (ptr = emfc->iflist_head; ptr != NULL; ptr = ptr->next)
1233 if (ptr->uffp_ref == 0)
1234 continue;
1236 bytes += sizeof(emf_cfg_uffp_t);
1237 if (bytes > size)
1238 return (FAILURE);
1240 strncpy(list->uffp_entry[index].if_name, DEV_IFNAME(ptr->ifp), 16);
1241 list->uffp_entry[index].if_name[15] = 0;
1242 index++;
1245 /* Update the total number of entries */
1246 list->num_entries = index;
1248 return (SUCCESS);
1252 * Description: This function is called by the IGMP Snooper to add a Router
1253 * Port. Router Port is the interface on which the IGMP Snooper
1254 * determines that a multicast router is present. We set a bit
1255 * in the flag field of the interface list entry to mark it as
1256 * router port.
1258 * Input: emfc - EMFC Global Instance handle
1259 * ifp - Interface pointer
1261 * Return: SUCCESS/FAILURE
1263 int32
1264 emfc_rtport_add(emfc_info_t *emfc, void *ifp)
1266 emfc_iflist_t *iflist, *prev;
1268 /* Add interface list entry */
1269 emfc_iflist_add(emfc, ifp);
1271 OSL_LOCK(emfc->iflist_lock);
1272 if ((iflist = emfc_iflist_find(emfc, ifp, &prev)) != NULL)
1273 iflist->rtport_ref++;
1274 OSL_UNLOCK(emfc->iflist_lock);
1276 EMF_INFO("RTPORT %s added refcount %d\n", DEV_IFNAME(ifp), iflist->rtport_ref);
1278 return (SUCCESS);
1282 * Description: This function is called by the IGMP Snooper to delete a
1283 * Router Port. We clear the corresponding bit in the flags
1284 * field to mark the port as non-router port.
1286 * Input: emfc - EMFC Global Instance handle
1287 * ifp - Interface pointer
1289 * Return: SUCCESS/FAILURE
1291 int32
1292 emfc_rtport_del(emfc_info_t *emfc, void *ifp)
1294 emfc_iflist_t *iflist, *prev;
1296 if ((iflist = emfc_iflist_find(emfc, ifp, &prev)) == NULL)
1298 EMF_ERROR("Invalid interface specified to rtport delete\n");
1299 return (FAILURE);
1302 /* Delete the interface entry when flags is zero */
1303 OSL_LOCK(emfc->iflist_lock);
1304 iflist->rtport_ref--;
1305 if ((iflist->rtport_ref == 0) && (iflist->uffp_ref == 0))
1306 emfc_iflist_del(emfc, ifp);
1307 OSL_UNLOCK(emfc->iflist_lock);
1309 return (SUCCESS);
1313 * RTPORT listing function
1315 static int32
1316 emfc_rtport_list(emfc_info_t *emfc, emf_cfg_rtport_list_t *list, uint32 size)
1318 int32 index = 0, bytes = 0;
1319 emfc_iflist_t *ptr;
1321 for (ptr = emfc->iflist_head; ptr != NULL; ptr = ptr->next)
1323 if (ptr->rtport_ref == 0)
1324 continue;
1326 bytes += sizeof(emf_cfg_rtport_t);
1327 if (bytes > size)
1328 return (FAILURE);
1330 strncpy(list->rtport_entry[index].if_name, DEV_IFNAME(ptr->ifp), 16);
1331 list->rtport_entry[index].if_name[15] = 0;
1332 index++;
1335 /* Update the total number of entries */
1336 list->num_entries = index;
1338 return (SUCCESS);
1342 * Description: This function is called from the OS Specific layer when the
1343 * user issues a configuration command.
1345 * Input/Output: Same as emfc_cfg_emf_enable.
1347 void
1348 emfc_cfg_request_process(emfc_info_t *emfc, emf_cfg_request_t *cfg)
1350 emf_cfg_mfdb_t *mfdb;
1351 emf_cfg_uffp_t *uffp;
1352 emf_cfg_rtport_t *rtport;
1354 EMF_DEBUG("Command identifier: %d\n", cfg->command_id);
1356 switch (cfg->command_id)
1358 case EMFCFG_CMD_EMF_ENABLE:
1359 emfc_cfg_emf_enable(emfc, cfg);
1360 break;
1362 case EMFCFG_CMD_MFDB_ADD:
1363 mfdb = (emf_cfg_mfdb_t *)cfg->arg;
1364 cfg->size = 0;
1366 /* Add MFDB entry for this group and interface */
1367 if (emfc_mfdb_membership_add(emfc, mfdb->mgrp_ip,
1368 mfdb->if_ptr) != SUCCESS)
1370 cfg->status = EMFCFG_STATUS_FAILURE;
1371 cfg->size += sprintf(cfg->arg, "Unable to add entry\n");
1372 break;
1375 cfg->status = EMFCFG_STATUS_SUCCESS;
1377 EMF_MFDB("MFDB entry %x %p added by user\n",
1378 mfdb->mgrp_ip, mfdb->if_ptr);
1379 break;
1381 case EMFCFG_CMD_MFDB_DEL:
1382 mfdb = (emf_cfg_mfdb_t *)cfg->arg;
1383 cfg->size = 0;
1385 /* Delete MFDB entry */
1386 if (emfc_mfdb_membership_del(emfc, mfdb->mgrp_ip,
1387 mfdb->if_ptr) != SUCCESS)
1389 cfg->status = EMFCFG_STATUS_FAILURE;
1390 cfg->size += sprintf(cfg->arg, "MFDB entry not found\n");
1391 break;
1394 cfg->status = EMFCFG_STATUS_SUCCESS;
1396 EMF_MFDB("MFDB entry %x %p deleted by user\n",
1397 mfdb->mgrp_ip, mfdb->if_ptr);
1398 break;
1400 case EMFCFG_CMD_MFDB_LIST:
1401 if (emfc_mfdb_list(emfc, (emf_cfg_mfdb_list_t *)cfg->arg,
1402 cfg->size) != SUCCESS)
1404 cfg->status = EMFCFG_STATUS_FAILURE;
1405 cfg->size += sprintf(cfg->arg, "MFDB list get failed\n");
1406 break;
1409 cfg->status = EMFCFG_STATUS_SUCCESS;
1410 break;
1412 case EMFCFG_CMD_MFDB_CLEAR:
1413 emfc_mfdb_clear(emfc);
1414 cfg->status = EMFCFG_STATUS_SUCCESS;
1415 break;
1417 case EMFCFG_CMD_RTPORT_ADD:
1418 rtport = (emf_cfg_rtport_t *)cfg->arg;
1419 cfg->size = 0;
1421 if (emfc_rtport_add(emfc, rtport->if_ptr) != SUCCESS)
1423 cfg->status = EMFCFG_STATUS_FAILURE;
1424 cfg->size += sprintf(cfg->arg,
1425 "Unknown interface, rtport add failed\n");
1426 break;
1429 cfg->status = EMFCFG_STATUS_SUCCESS;
1430 break;
1432 case EMFCFG_CMD_RTPORT_DEL:
1433 rtport = (emf_cfg_rtport_t *)cfg->arg;
1434 cfg->size = 0;
1436 if (emfc_rtport_del(emfc, rtport->if_ptr) != SUCCESS)
1438 cfg->status = EMFCFG_STATUS_FAILURE;
1439 cfg->size += sprintf(cfg->arg,
1440 "Unknown interface, rtport del failed\n");
1441 break;
1444 cfg->status = EMFCFG_STATUS_SUCCESS;
1445 break;
1447 case EMFCFG_CMD_RTPORT_LIST:
1448 if (emfc_rtport_list(emfc, (emf_cfg_rtport_list_t *)cfg->arg,
1449 cfg->size) != SUCCESS)
1451 cfg->status = EMFCFG_STATUS_FAILURE;
1452 cfg->size = sprintf(cfg->arg, "rtport list get failed\n");
1453 break;
1456 cfg->status = EMFCFG_STATUS_SUCCESS;
1457 break;
1459 case EMFCFG_CMD_UFFP_ADD:
1460 uffp = (emf_cfg_uffp_t *)cfg->arg;
1461 cfg->size = 0;
1463 if (emfc_uffp_add(emfc, uffp->if_ptr) != SUCCESS)
1465 cfg->status = EMFCFG_STATUS_FAILURE;
1466 cfg->size += sprintf(cfg->arg,
1467 "Unknown interface, UFFP add failed\n");
1468 break;
1471 cfg->status = EMFCFG_STATUS_SUCCESS;
1472 break;
1474 case EMFCFG_CMD_UFFP_DEL:
1475 uffp = (emf_cfg_uffp_t *)cfg->arg;
1476 cfg->size = 0;
1478 if (emfc_uffp_del(emfc, uffp->if_ptr) != SUCCESS)
1480 cfg->status = EMFCFG_STATUS_FAILURE;
1481 cfg->size += sprintf(cfg->arg,
1482 "Unknown interface, UFFP del failed\n");
1483 break;
1486 cfg->status = EMFCFG_STATUS_SUCCESS;
1487 break;
1489 case EMFCFG_CMD_UFFP_LIST:
1490 if (emfc_uffp_list(emfc, (emf_cfg_uffp_list_t *)cfg->arg,
1491 cfg->size) != SUCCESS)
1493 cfg->status = EMFCFG_STATUS_FAILURE;
1494 cfg->size = sprintf(cfg->arg, "UFFP list get failed\n");
1495 break;
1498 cfg->status = EMFCFG_STATUS_SUCCESS;
1499 break;
1501 case EMFCFG_CMD_EMF_STATS:
1502 if (emfc_stats_get(emfc, (emf_stats_t *)cfg->arg,
1503 cfg->size) != SUCCESS)
1505 cfg->status = EMFCFG_STATUS_FAILURE;
1506 cfg->size = sprintf(cfg->arg, "EMF stats get failed\n");
1507 break;
1510 cfg->status = EMFCFG_STATUS_SUCCESS;
1511 break;
1513 default:
1514 EMF_DEBUG("Unknown command %d\n", cfg->command_id);
1515 cfg->status = EMFCFG_STATUS_CMD_UNKNOWN;
1516 cfg->size = sprintf(cfg->arg, "Unknown command\n");
1517 break;
1520 return;
1524 * Description: This function is called from the OS specific module init
1525 * routine to create and initialize EMFC instance. This function
1526 * primarily initializes the EMFL global data and MFDB.
1528 * Input: inst_id - Instance identier used to associate EMF
1529 * and IGMP snooper instances.
1530 * emfi - EMFL OS Specific global data handle
1531 * osh - OS abstraction layer handle
1532 * wrapper - EMFC wrapper info
1534 * Return: emfc - EMFL Common code global data handle
1536 emfc_info_t *
1537 emfc_init(int8 *inst_id, void *emfi, osl_t *osh, emfc_wrapper_t *wrapper)
1539 emfc_info_t *emfc;
1541 EMF_DEBUG("Initializing EMFL\n");
1543 /* Check for the wrapper parameter */
1544 if (wrapper == NULL)
1546 EMF_ERROR("emfc_init: wrapper parameter NULL\n");
1547 return (NULL);
1550 /* Allocate memory */
1551 emfc = MALLOC(osh, sizeof(emfc_info_t));
1552 if (emfc == NULL)
1554 EMF_ERROR("Failed to allocated memory size %d for MFL\n",
1555 sizeof(emfc_info_t));
1556 return (NULL);
1559 EMF_DEBUG("Allocated memory for EMFC info\n");
1561 /* Initialize the EMF global data */
1562 bzero(emfc, sizeof(emfc_info_t));
1563 emfc->osh = osh;
1564 emfc->emfi = emfi;
1565 emfc->mgrp_cache_ip = 0;
1566 emfc->mgrp_cache = NULL;
1567 emfc->iflist_head = NULL;
1569 /* Set EMF status as disabled */
1570 emfc->emf_enable = FALSE;
1572 /* Initialize Multicast FDB */
1573 emfc_mfdb_init(emfc);
1575 /* Create lock for MFDB access */
1576 emfc->fdb_lock = OSL_LOCK_CREATE("FDB Lock");
1577 if (emfc->fdb_lock == NULL)
1579 MFREE(emfc->osh, emfc, sizeof(emfc_info_t));
1580 return (NULL);
1583 /* Create lock for router port list access */
1584 emfc->iflist_lock = OSL_LOCK_CREATE("Router Port List Lock");
1585 if (emfc->iflist_lock == NULL)
1587 OSL_LOCK_DESTROY(emfc->fdb_lock);
1588 MFREE(emfc->osh, emfc, sizeof(emfc_info_t));
1589 return (NULL);
1592 /* Save the instance id */
1593 strncpy(emfc->inst_id, inst_id, IFNAMSIZ);
1594 emfc->inst_id[IFNAMSIZ - 1] = 0;
1596 /* Fill up the wrapper specific functions */
1597 emfc->wrapper.forward_fn = wrapper->forward_fn;
1598 emfc->wrapper.sendup_fn = wrapper->sendup_fn;
1599 emfc->wrapper.hooks_register_fn = wrapper->hooks_register_fn;
1600 emfc->wrapper.hooks_unregister_fn = wrapper->hooks_unregister_fn;
1602 /* Add to the EMFC instance list */
1603 OSL_LOCK(emfc_list_lock);
1604 clist_add_head(&emfc_list_head, &emfc->emfc_list);
1605 OSL_UNLOCK(emfc_list_lock);
1607 EMF_DEBUG("Initialized MFDB\n");
1609 return (emfc);
1613 * Description: This function is called from OS specific module cleanup
1614 * routine. This routine primarily clears the MFDB entries
1615 * and frees the global instance data.
1617 * Input: emfc - EMFL global instance handle
1619 void
1620 emfc_exit(emfc_info_t *emfc)
1622 emfc_mhif_t *ptr, *temp;
1624 /* Unregister the packet hooks if not already */
1625 emfc->wrapper.hooks_unregister_fn(emfc->emfi);
1627 /* Cleanup MFDB entries */
1628 emfc_mfdb_clear(emfc);
1630 /* Cleanup the interface list entries */
1631 emfc_iflist_clear(emfc);
1632 OSL_LOCK_DESTROY(emfc->iflist_lock);
1634 OSL_LOCK(emfc->fdb_lock);
1636 /* Delete interface list */
1637 ptr = emfc->mhif_head;
1638 while (ptr != NULL)
1640 temp = ptr->next;
1641 MFREE(emfc->osh, ptr, sizeof(emfc_mhif_t));
1642 ptr = temp;
1645 OSL_UNLOCK(emfc->fdb_lock);
1647 OSL_LOCK_DESTROY(emfc->fdb_lock);
1649 /* Delete the EMFC instance */
1650 OSL_LOCK(emfc_list_lock);
1651 clist_delete(&emfc->emfc_list);
1652 OSL_UNLOCK(emfc_list_lock);
1654 MFREE(emfc->osh, emfc, sizeof(emfc_info_t));
1656 EMF_DEBUG("Cleaned up EMFL, exiting common code\n");
1658 return;
1662 * Description: This function is called from OS specific module init
1663 * routine. This allocates global resources required by the
1664 * common code.
1666 int32
1667 emfc_module_init(void)
1669 /* Create lock for EMFC instance list access */
1670 emfc_list_lock = OSL_LOCK_CREATE("EMFC List Lock");
1672 if (emfc_list_lock == NULL)
1674 EMF_ERROR("EMFC List lock create failed\n");
1675 return (FAILURE);
1678 return (SUCCESS);
1682 * Description: This function is called from OS specific module cleanup
1683 * routine. This frees all the global resources.
1685 void
1686 emfc_module_exit(void)
1688 OSL_LOCK_DESTROY(emfc_list_lock);
1689 return;