GUI: Fix Tomato RAF theme for all builds. Compilation typo.
[tomato.git] / release / src-rt-6.x.4708 / emf / igs / igsc.c
blob1a453d3cb7cfd1cb0b369060c009256f6da0ad80
1 /*
2 * IGMP Snooping Layer: IGMP Snooping module runs at layer 2. IGMP
3 * Snooping layer uses the multicast information in the IGMP messages
4 * exchanged between the participating hosts and multicast routers to
5 * update the multicast forwarding database. This file contains the
6 * common code routines of IGS module.
8 * Copyright (C) 2012, Broadcom Corporation
9 * All Rights Reserved.
11 * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom Corporation;
12 * the contents of this file may not be disclosed to third parties, copied
13 * or duplicated in any form, in whole or in part, without the prior
14 * written permission of Broadcom Corporation.
16 * $Id: igsc.c 393595 2013-03-28 03:46:05Z $
19 #include <typedefs.h>
20 #include <bcmdefs.h>
21 #include <bcmendian.h>
22 #include <proto/bcmip.h>
23 #include <osl.h>
24 #include <bcmnvram.h>
25 #include <clist.h>
26 #if defined(linux)
27 #include <osl_linux.h>
28 #elif defined(__ECOS)
29 #include <osl_ecos.h>
30 #else /* defined(osl_xx) */
31 #error "Unsupported osl"
32 #endif /* defined(osl_xx) */
33 #include "igs_cfg.h"
34 #include "emfc_export.h"
35 #include "igs_export.h"
36 #include "igsc_export.h"
37 #include "igsc.h"
38 #include "igsc_sdb.h"
40 static mc_grp_spl_t mc_addr_rsvd[] =
42 { 0xe0000001, 0xffffffff }, /* All hosts */
43 { 0xe0000002, 0xffffffff }, /* All routers */
44 { 0xe0000004, 0xffffffff }, /* DVMRP routers */
45 { 0xe0000005, 0xffffffff }, /* OSPF1 routers */
46 { 0xe0000006, 0xffffffff }, /* OSPF2 routers */
47 { 0xe0000009, 0xffffffff }, /* RIP v2 routers */
48 { 0xe000000d, 0xffffffff }, /* PIMd routers */
49 { 0xe0000010, 0xffffffff }, /* IGMP v3 routers */
50 { 0xe00000fb, 0xffffffff }, /* Reserved */
51 { 0xe000ff87, 0xffffffff }, /* Reserved */
52 { 0xeffffffa, 0xffffffff }, /* UPnP */
55 static bool
56 igsc_is_reserved(uint32 addr)
58 int32 i;
60 for (i = 0; i < sizeof(mc_addr_rsvd)/sizeof(mc_grp_spl_t); i++)
62 if ((addr & mc_addr_rsvd[i].mask) ==
63 (mc_addr_rsvd[i].addr & mc_addr_rsvd[i].mask))
65 return (TRUE);
69 return (FALSE);
73 * Description: This function is called if the snooper doesn't receive
74 * membership query from a router for timeout interval.
75 * It deletes the router port entry from the list. If this
76 * is the last router on the interface then the EMF router
77 * port entry is also deleted.
79 * Input: rtlist_ptr - Multicast router interface/port entry
81 void
82 igsc_rtlist_timer(igsc_rtlist_t *rtlist_ptr)
84 clist_head_t *ptr;
85 igsc_rtlist_t *rtl_ptr;
86 bool mr_port_found = FALSE;
87 igsc_info_t *igsc_info;
89 igsc_info = rtlist_ptr->igsc_info;
91 /* Delete the expired router port entry */
92 clist_delete(&rtlist_ptr->list);
94 /* Check if there are more routers on this port/interface */
95 for (ptr = igsc_info->rtlist_head.next;
96 ptr != &igsc_info->rtlist_head; ptr = ptr->next)
98 rtl_ptr = clist_entry(ptr, igsc_rtlist_t, list);
99 if (rtl_ptr->ifp == rtlist_ptr->ifp)
101 mr_port_found = TRUE;
102 break;
106 /* Last multicast router on this port/interface */
107 if (!mr_port_found)
109 IGS_DEBUG("Delete the router port %p in the EMF\n",
110 rtlist_ptr->ifp);
111 emfc_rtport_del(igsc_info->emf_handle, rtlist_ptr->ifp);
114 MFREE(igsc_info->osh, rtlist_ptr, sizeof(igsc_rtlist_t));
116 return;
120 * Description: This function is called to find the entry in the router
121 * port list given the IP Address and the interface pointer.
123 * Input: igsc_info - IGSC Global Instance handle
124 * ifp - Interface pointer
125 * mr_ip - IP address of the router
127 * Return: Pointer to the entry found or NULL otherwise
129 static igsc_rtlist_t *
130 igsc_rtlist_find(igsc_info_t *igsc_info, void *ifp, uint32 mr_ip)
132 clist_head_t *ptr;
133 igsc_rtlist_t *rtl_ptr;
135 OSL_LOCK(igsc_info->rtlist_lock);
137 for (ptr = igsc_info->rtlist_head.next;
138 ptr != &igsc_info->rtlist_head; ptr = ptr->next)
140 rtl_ptr = clist_entry(ptr, igsc_rtlist_t, list);
142 if ((rtl_ptr->ifp == ifp) && (rtl_ptr->mr_ip == mr_ip))
144 OSL_UNLOCK(igsc_info->rtlist_lock);
145 IGS_DEBUG("Router port entry %x %p found\n",
146 mr_ip, ifp);
147 return (rtl_ptr);
151 OSL_UNLOCK(igsc_info->rtlist_lock);
153 return (NULL);
157 * Description: This function is called when the snooper receives IGMP
158 * membership query on one of the ports. It adds an entry
159 * to the multicast router port list. Each entry of the
160 * list contains the IP address of the multicast router
161 * and the interface/port on which it is present. It calls
162 * the EMF function to add a router port entry to the list
163 * maintained by EMF.
165 * Input: igsc_info - IGSC Global Instance handle
166 * ifp - Interface pointer
167 * mr_ip - IP address of the router
169 * Return: SUCCESS/FAILURE
171 int32
172 igsc_rtlist_add(igsc_info_t *igsc_info, void *ifp, uint32 mr_ip)
174 igsc_rtlist_t *rtlist_ptr;
176 /* If the router port list entry exists already then refresh the
177 * timer for this entry.
179 if ((rtlist_ptr = igsc_rtlist_find(igsc_info, ifp, mr_ip)) != NULL)
181 osl_timer_update(rtlist_ptr->rtlist_timer, igsc_info->query_intv,
182 FALSE);
183 IGS_DEBUG("Duplicate router port entry %x %p\n", mr_ip, ifp);
184 return (FAILURE);
187 /* Allocate and intialize the entry */
188 rtlist_ptr = MALLOC(igsc_info->osh, sizeof(igsc_rtlist_t));
189 if (rtlist_ptr == NULL)
191 IGS_ERROR("Failed to allocate memory size %d for rtport list\n",
192 sizeof(igsc_rtlist_t));
193 return (FAILURE);
196 rtlist_ptr->ifp = ifp;
197 rtlist_ptr->mr_ip = mr_ip;
198 rtlist_ptr->igsc_info = igsc_info;
200 OSL_LOCK(igsc_info->rtlist_lock);
202 /* Add the entry to the EMF router port list */
203 if (emfc_rtport_add(igsc_info->emf_handle, ifp) != SUCCESS)
205 OSL_UNLOCK(igsc_info->rtlist_lock);
206 MFREE(igsc_info->osh, rtlist_ptr, sizeof(igsc_rtlist_t));
207 IGS_ERROR("Failed to add EMF rtport entry for %p\n", ifp);
208 return (FAILURE);
211 /* Add timer to delete the entry on igmp query timeout */
212 rtlist_ptr->rtlist_timer = osl_timer_init("MR_PORT_LIST_TIMER",
213 (void (*)(void *))igsc_rtlist_timer,
214 (void *)rtlist_ptr);
216 if (rtlist_ptr->rtlist_timer == NULL)
218 OSL_UNLOCK(igsc_info->rtlist_lock);
219 emfc_rtport_del(igsc_info->emf_handle, ifp);
220 MFREE(igsc_info->osh, rtlist_ptr, sizeof(igsc_rtlist_t));
221 IGS_ERROR("Failed to allocate memory size %d for timer\n",
222 sizeof(osl_timer_t));
223 return (FAILURE);
226 osl_timer_add(rtlist_ptr->rtlist_timer, igsc_info->query_intv, FALSE);
228 /* Add the entry to IGS router port list */
229 clist_add_head(&igsc_info->rtlist_head, &rtlist_ptr->list);
231 OSL_UNLOCK(igsc_info->rtlist_lock);
233 return (SUCCESS);
237 * Description: This function is called to clear the IGSC router port list.
238 * It also call the API to delete the corresponding EMF router
239 * port entry.
241 * Input: igsc_info - IGSC Global Instance handle
243 static void
244 igsc_rtlist_clear(igsc_info_t *igsc_info)
246 clist_head_t *ptr, *tmp;
247 igsc_rtlist_t *rtl_ptr;
249 OSL_LOCK(igsc_info->rtlist_lock);
251 for (ptr = igsc_info->rtlist_head.next;
252 ptr != &igsc_info->rtlist_head; ptr = tmp)
254 rtl_ptr = clist_entry(ptr, igsc_rtlist_t, list);
255 tmp = ptr->next;
256 osl_timer_del(rtl_ptr->rtlist_timer);
257 emfc_rtport_del(igsc_info->emf_handle, rtl_ptr->ifp);
258 clist_delete(ptr);
259 MFREE(igsc_info->osh, rtl_ptr, sizeof(igsc_rtlist_t));
262 OSL_UNLOCK(igsc_info->rtlist_lock);
264 return;
267 /* Add Joining Member or Update joined member */
268 static int32 igsc_update_join_member(igsc_info_t *igsc_info, void *ifp, uint32 dest_ip,
269 uint32 mcast_ip, uint32 mh_ip)
271 int32 ret = FAILURE;
273 if (igsc_is_reserved(mcast_ip)) {
274 IGSC_STATS_INCR(igsc_info, igmp_not_handled);
275 IGS_DEBUG("Reserved multicast address %x frame\n",
276 mcast_ip);
277 return ((ret == SUCCESS) ? EMF_FORWARD : EMF_FLOOD);
279 /* When a host membership report is received add/refresh the entry for the host. */
280 IGS_DEBUG("Join mcast_addr=%x\n", mcast_ip);
281 IGSC_STATS_INCR(igsc_info, igmp_v2reports);
283 ret = igsc_sdb_member_add(igsc_info, ifp, mcast_ip, mh_ip);
284 return ((ret == SUCCESS) ? EMF_FORWARD : EMF_FLOOD);
287 /* Remove leave members */
288 static int32 igsc_update_leave_member(igsc_info_t *igsc_info, void *ifp,
289 uint32 mcast_ip, uint32 mh_ip)
291 int32 ret = FAILURE;
293 IGSC_STATS_INCR(igsc_info, igmp_leaves);
294 IGS_DEBUG("Leave mcast_addr=%x\n", mcast_ip);
296 ret = igsc_sdb_member_del(igsc_info, ifp, mcast_ip, mh_ip);
298 if (ret != SUCCESS)
299 IGS_WARN("Deleting unknown member with grp %x host %x if %p",
300 igmpv3g->mcast_addr, mh_ip, ifp);
301 return ((ret == SUCCESS) ? EMF_FORWARD : EMF_FLOOD);
305 * Description: This function is called by EMFL when an IGMP frame
306 * is received. Based on the IGMP packet type it either
307 * adds, deletes or refreshes the MFDB entry.
309 * Input: s - Snooper global instance data cookie
310 * ifp - Pointer to interface the frame arrived on.
311 * iph - Points to start of IP header in the packet.
312 * igmph - Points to start of IGMP header in the packet.
313 * from_rp - TRUE when received from router port.
315 * Return: EMF_FLOOD - Flood the frame.
316 * EMF_SENDUP - Deliver the packet to IP layer.
318 static int32
319 igsc_input(emfc_snooper_t *s, void *ifp, uint8 *iph, uint8 *igmph, bool from_rp)
321 int32 ret = FAILURE;
322 igsc_info_t *igsc_info;
323 uint32 mgrp_ip, mh_ip, dest_ip;
324 uint16 grp_num = 0, offset;
325 igmpv3_report_t *igmpv3h;
326 igmpv3_group_t *igmpv3g;
328 ASSERT(s != NULL);
330 igsc_info = IGSC_INFO(s);
332 IGSC_STATS_INCR(igsc_info, igmp_packets);
334 if (from_rp)
336 IGS_DEBUG("Ignoring IGMP frame from router port\n");
337 IGSC_STATS_INCR(igsc_info, igmp_not_handled);
338 return (EMF_FLOOD);
341 mgrp_ip = ntoh32(*((uint32 *)(igmph + IGMPV2_GRP_ADDR_OFFSET)));
342 mh_ip = ntoh32(*((uint32 *)(iph + IPV4_SRC_IP_OFFSET)));
343 dest_ip = ntoh32(*((uint32 *)(iph + IPV4_DEST_IP_OFFSET)));
345 switch (igmph[IGMPV2_TYPE_OFFSET])
347 case IGMPV2_HOST_NEW_MEMBERSHIP_REPORT:
348 /* Move report to function igsc_update_join_member() */
349 ret = igsc_update_join_member(igsc_info, ifp, dest_ip, mgrp_ip, mh_ip);
350 #ifdef PLC /* PLC feature expecting reports to be flooded */
351 break;
352 #else
353 return ret;
354 #endif
356 case IGMPV2_LEAVE_GROUP_MESSAGE:
357 /* Move Leave to function igsc_update_leave_member() */
358 ret = igsc_update_leave_member(igsc_info, ifp, mgrp_ip, mh_ip);
359 break;
361 case IGMPV2_HOST_MEMBERSHIP_REPORT:
362 IGSC_STATS_INCR(igsc_info, igmp_reports);
363 break;
365 case IGMPV2_HOST_MEMBERSHIP_QUERY:
366 IGSC_STATS_INCR(igsc_info, igmp_queries);
368 /* Update the multicast router port list */
369 if (mh_ip != 0)
371 IGS_DEBUG("Updating router port list with %x %p\n",
372 mh_ip, ifp);
373 igsc_rtlist_add(igsc_info, ifp, mh_ip);
375 break;
376 case IGMPV3_HOST_MEMBERSHIP_REPORT:
377 igmpv3h = (igmpv3_report_t *)igmph;
378 igmpv3g = (igmpv3_group_t*)(igmpv3h+1);
380 IGS_DEBUG("group_num=%d\n", ntoh16(*(uint16 *)&igmpv3h->group_num));
382 for (grp_num = 0; grp_num < ntoh16(*(uint16 *)&igmpv3h->group_num);
383 grp_num++) {
385 switch (igmpv3g->type) {
386 case IGMPV3_MODE_IS_EXCLUDE:
387 case IGMPV3_ALLOW_NEW_SOURCES:
388 case IGMPV3_BLOCK_OLD_SOURCES:
389 case IGMPV3_CHANGE_TO_EXCLUDE:
390 mgrp_ip = ntoh32(*(uint32 *)&igmpv3g->mcast_addr);
392 IGS_DEBUG("Leave mcast_addr=%x, src_num=%x\n",
393 mgrp_ip,
394 ntoh16(*(uint16 *)&igmpv3g->src_num));
396 if (!IP_ISMULTI(mgrp_ip))
397 IGS_ERROR("ADD mgrp_ip=%x\n", mgrp_ip);
398 else
399 ret = igsc_update_join_member(igsc_info,
400 ifp, dest_ip, mgrp_ip, mh_ip);
401 break;
403 case IGMPV3_CHANGE_TO_INCLUDE:
404 case IGMPV3_MODE_IS_INCLUDE:
405 mgrp_ip = ntoh32(*(uint32 *)&igmpv3g->mcast_addr);
407 IGS_DEBUG("Leave mcast_addr=%x, src_num=%x\n",
408 mgrp_ip,
409 ntoh16(*(uint16 *)&igmpv3g->src_num));
411 if (!IP_ISMULTI(mgrp_ip)) {
412 IGS_ERROR("CHANGE mgrp_ip=%x\n", mgrp_ip);
413 break;
416 if (ntoh32(igmpv3g->src_num) == 0)
417 ret = igsc_update_leave_member(igsc_info,
418 ifp, mgrp_ip, mh_ip);
419 else
420 ret = igsc_update_join_member(igsc_info,
421 ifp, dest_ip, mgrp_ip, mh_ip);
422 break;
423 default:
424 IGS_ERROR("IGMPV3 type=%x\n", igmpv3g->type);
425 break;
428 offset = sizeof(igmpv3_group_t)+
429 igmpv3g->src_num*IGMPV3_SRC_ADDR_LEN + igmpv3g->aux_len;
430 igmpv3g = (igmpv3_group_t*)(((unsigned char *)igmpv3g)+offset);
432 break;
434 default:
435 IGS_WARN("IGMP type %d not handled\n", igmph[IGMPV2_TYPE_OFFSET]);
436 IGSC_STATS_INCR(igsc_info, igmp_not_handled);
437 break;
440 return (EMF_FLOOD);
444 * Internet checksum routine
446 static uint16
447 inet_cksum(uint8 *buf, int32 len)
449 uint32 sum = 0;
450 uint16 val;
452 while (len > 1)
454 val = *buf++ << 8;
455 val |= *buf++;
456 sum += val;
457 len -= 2;
460 if (len > 0)
462 sum += (*buf) << 8;
465 while (sum >> 16)
467 sum = (sum & 0xffff) + (sum >> 16);
470 return (hton16(~sum));
474 * Description: This function adds the IP header, IGMP header and data.
476 static void
477 igsc_igmp_pkt_encap(uint8 *ip, uint32 src_ip, uint32 dest_ip,
478 uint8 igmp_type, uint8 max_rsp, uint32 grp_addr)
480 uint8 *igmp;
482 /* Prepare the IP header */
483 ip[IP_VER_OFFSET] = ((IP_VER_4 << 4) | (IPV4_MIN_HLEN >> 2));
484 ip[IPV4_TOS_OFFSET] = 0xc0;
485 *((uint16 *)(ip + IPV4_LEN_OFFSET)) = hton16(IPV4_MIN_HLEN + IGMP_HLEN);
486 *((uint16 *)(ip + IPV4_ID_OFFSET)) = 0;
487 *((uint16 *)(ip + IPV4_FRAG_OFFSET)) = 0;
488 ip[IPV4_TTL_OFFSET] = 1;
489 ip[IPV4_PROT_OFFSET] = IP_PROT_IGMP;
490 *((uint16 *)(ip + IPV4_CHKSUM_OFFSET)) = 0;
491 *((uint32 *)(ip + IPV4_SRC_IP_OFFSET)) = src_ip;
492 *((uint32 *)(ip + IPV4_DEST_IP_OFFSET)) = dest_ip;
493 *((uint16 *)(ip + IPV4_CHKSUM_OFFSET)) = inet_cksum(ip, IPV4_MIN_HLEN);
495 /* Fill the IGMP header fields */
496 igmp = ip + IPV4_MIN_HLEN;
497 igmp[IGMPV2_TYPE_OFFSET] = igmp_type;
498 igmp[IGMPV2_MAXRSP_TIME_OFFSET] = max_rsp;
499 *((uint16 *)(igmp + IGMPV2_CHECKSUM_OFFSET)) = 0;
500 *((uint32 *)(igmp + IGMPV2_GRP_ADDR_OFFSET)) = grp_addr;
501 *((uint16 *)(igmp + IGMPV2_CHECKSUM_OFFSET)) = inet_cksum(ip,
502 IGMP_HLEN + IPV4_MIN_HLEN);
504 return;
508 * Description: This functions generates an IGMP Query. It is used to
509 * quickly determine the group members on the attached bridge
510 * ports.
512 * Return: SUCCESS or FAILURE
514 static int32
515 igsc_igmp_query_send(igsc_info_t *igsc_info)
517 uint32 ip[64];
518 uint32 lan_ip = 0;
520 /* Build the IGMP Query packet */
521 igsc_igmp_pkt_encap((uint8 *)ip, lan_ip, hton32(IPV4_MCADDR_ALLHOSTS),
522 IGMPV2_HOST_MEMBERSHIP_QUERY, IGMPV2_MAXRSP_TIME / 100, 0);
524 IGS_DEBUG("Forwarding IGMP Query on to bridge ports\n");
526 return (igsc_info->wrapper.igs_broadcast(igsc_info->igs_info, (uint8 *)ip,
527 IGMP_HLEN + IPV4_MIN_HLEN,
528 IPV4_MCADDR_ALLHOSTS));
532 * Description: This function is called by the EMFL when forwarding
533 * is enabled.
535 * Input: snooper - Snooper gloabl instance data.
537 * Return: SUCCESS or FAILURE
539 static int32
540 igsc_emf_enabled(emfc_snooper_t *snooper)
542 IGS_INFO("EMF enable callback called\n");
544 /* Send an IGMP Query packet to quickly learn the members present
545 * in the network.
547 if (igsc_igmp_query_send(IGSC_INFO(snooper)) != SUCCESS)
549 IGS_ERROR("IGMP Query send failed\n");
550 return (FAILURE);
553 return (SUCCESS);
557 * Description: This function is called by the EMFL when forwarding
558 * is disabled.
560 * Input: snooper - Snooper gloabl instance data.
562 * Return: SUCCESS or FAILURE
564 static int32
565 igsc_emf_disabled(emfc_snooper_t *snooper)
567 IGS_INFO("EMF disable callback\n");
568 igsc_sdb_clear(IGSC_INFO(snooper));
569 igsc_rtlist_clear(IGSC_INFO(snooper));
570 return (SUCCESS);
574 * IGSL Packet Counters/Statistics Function
576 int32
577 igsc_stats_get(igsc_info_t *igsc_info, igs_stats_t *stats, uint32 size)
579 if (igsc_info == NULL)
581 IGS_ERROR("Invalid IGSC handle passed\n");
582 return (FAILURE);
585 if (stats == NULL)
587 IGS_ERROR("Invalid buffer input\n");
588 return (FAILURE);
591 if (size < sizeof(igs_stats_t))
593 IGS_ERROR("Insufficient buffer size %d\n", size);
594 return (FAILURE);
597 *stats = igsc_info->stats;
599 return (SUCCESS);
603 * RTPORT Interface Listing
605 static int32
606 igsc_rtport_list(igsc_info_t *igsc, igs_cfg_rtport_list_t *list, uint32 size)
608 int32 index = 0, bytes = 0;
609 clist_head_t *ptr;
610 igsc_rtlist_t *rtl_ptr;
612 for (ptr = igsc->rtlist_head.next; ptr != &igsc->rtlist_head; ptr = ptr->next)
614 rtl_ptr = clist_entry(ptr, igsc_rtlist_t, list);
616 bytes += sizeof(igs_cfg_rtport_list_t);
617 if (bytes > size)
618 return (FAILURE);
620 list->rtport_entry[index].mr_ip = rtl_ptr->mr_ip;
621 strncpy(list->rtport_entry[index].if_name, DEV_IFNAME(rtl_ptr->ifp), 16);
622 index++;
625 /* Update the total number of entries */
626 list->num_entries = index;
628 return (SUCCESS);
631 void
632 igsc_cfg_request_process(igsc_info_t *igsc_info, igs_cfg_request_t *cfg)
634 IGS_DEBUG("IGS command identifier: %d\n", cfg->command_id);
636 switch (cfg->command_id)
638 case IGSCFG_CMD_IGS_STATS:
639 if (igsc_stats_get(igsc_info, (igs_stats_t *)cfg->arg,
640 cfg->size) != SUCCESS)
642 cfg->status = IGSCFG_STATUS_FAILURE;
643 cfg->size = sprintf(cfg->arg, "IGS stats get failed\n");
644 break;
646 cfg->status = IGSCFG_STATUS_SUCCESS;
647 break;
649 case IGSCFG_CMD_IGSDB_LIST:
650 if (igsc_sdb_list(igsc_info, (igs_cfg_sdb_list_t *)cfg->arg,
651 cfg->size) != SUCCESS)
653 cfg->status = IGSCFG_STATUS_FAILURE;
654 cfg->size = sprintf(cfg->arg, "IGSDB listing failed\n");
655 break;
657 cfg->status = IGSCFG_STATUS_SUCCESS;
658 break;
660 case IGSCFG_CMD_RTPORT_LIST:
661 if (igsc_rtport_list(igsc_info, (igs_cfg_rtport_list_t *)cfg->arg,
662 cfg->size) != SUCCESS)
664 cfg->status = EMFCFG_STATUS_FAILURE;
665 cfg->size = sprintf(cfg->arg, "RTPORT list get failed\n");
666 break;
668 cfg->status = EMFCFG_STATUS_SUCCESS;
669 break;
671 default:
672 cfg->status = IGSCFG_STATUS_CMD_UNKNOWN;
673 cfg->size = sprintf(cfg->arg, "Unknown command id %d\n",
674 cfg->command_id);
675 break;
680 * Description: This function is called from the OS specific module
681 * init routine to initialize the IGSL. This function
682 * primarily initializes the IGSL global data and IGSDB.
684 * Input: inst_id - IGS instance identifier.
685 * igs_info - IGSL OS Specific global data handle
686 * osh - OS abstraction layer handle
687 * wrapper - wrapper specific info
689 * Return: igsc_info - IGSL Common code global data handle
691 void *
692 igsc_init(int8 *inst_id, void *igs_info, osl_t *osh, igsc_wrapper_t *wrapper)
694 igsc_info_t *igsc_info;
696 if (inst_id == NULL)
698 IGS_ERROR("Instance identifier NULL\n");
699 return (NULL);
702 if (wrapper == NULL)
704 IGS_ERROR("wrapper info NULL\n");
705 return (NULL);
708 IGS_DEBUG("Initializing IGMP Snooping Layer\n");
710 /* Allocate memory */
711 igsc_info = MALLOC(osh, sizeof(igsc_info_t));
712 if (igsc_info == NULL)
714 IGS_ERROR("Failed to allocated memory size %d for MFL\n",
715 sizeof(igsc_info_t));
716 return (NULL);
719 IGS_DEBUG("Allocated memory for IGSC info\n");
721 /* Initialize the IGS global data */
722 bzero(igsc_info, sizeof(igsc_info_t));
723 igsc_info->osh = osh;
724 igsc_info->igs_info = igs_info;
725 igsc_info->grp_mem_intv = IGMPV2_GRP_MEM_INTV;
726 igsc_info->query_intv = IGMPV2_QUERY_INTV;
728 /* Fill in the wrapper specific data */
729 igsc_info->wrapper.igs_broadcast = wrapper->igs_broadcast;
731 /* Initialize the IGSDB */
732 igsc_sdb_init(igsc_info);
734 igsc_info->sdb_lock = OSL_LOCK_CREATE("SDB Lock");
736 if (igsc_info->sdb_lock == NULL)
738 igsc_sdb_clear(igsc_info);
739 MFREE(osh, igsc_info, sizeof(igsc_info_t));
740 return (NULL);
743 /* Register IGMP v2 Snooper with EMFL */
744 igsc_info->snooper.input_fn = igsc_input;
745 igsc_info->snooper.emf_enable_fn = igsc_emf_enabled;
746 igsc_info->snooper.emf_disable_fn = igsc_emf_disabled;
748 if (emfc_igmp_snooper_register(inst_id, &igsc_info->emf_handle,
749 &igsc_info->snooper) != SUCCESS)
751 IGS_ERROR("IGMP Snooper couldn't register with EMF\n");
752 igsc_sdb_clear(igsc_info);
753 OSL_LOCK_DESTROY(igsc_info->sdb_lock);
754 MFREE(osh, igsc_info, sizeof(igsc_info_t));
755 return (NULL);
758 /* Initialize router port list head */
759 clist_init_head(&igsc_info->rtlist_head);
761 igsc_info->rtlist_lock = OSL_LOCK_CREATE("Router List Lock");
763 if (igsc_info->rtlist_lock == NULL)
765 emfc_igmp_snooper_unregister(igsc_info->emf_handle);
766 igsc_sdb_clear(igsc_info);
767 OSL_LOCK_DESTROY(igsc_info->sdb_lock);
768 MFREE(osh, igsc_info, sizeof(igsc_info_t));
769 return (NULL);
772 IGS_DEBUG("Initialized IGSDB\n");
774 return (igsc_info);
778 * Description: This function is called from OS specific module cleanup
779 * routine. This routine primarily stops the group interval
780 * timers and cleans up the IGSDB entries.
782 void
783 igsc_exit(igsc_info_t *igsc_info)
785 emfc_igmp_snooper_unregister(igsc_info->emf_handle);
787 /* Cleanup the IGS router port list entries */
788 igsc_rtlist_clear(igsc_info);
789 OSL_LOCK_DESTROY(igsc_info->rtlist_lock);
791 /* Cleanup the IGSDB */
792 igsc_sdb_clear(igsc_info);
793 OSL_LOCK_DESTROY(igsc_info->sdb_lock);
795 MFREE(igsc_info->osh, igsc_info, sizeof(igsc_info_t));
797 IGS_DEBUG("Cleaned up IGSL, exiting common code\n");
799 return;
804 * Description: This function is called to delete the IGSDB
805 * rtport entries on an interface
807 * Input: igsc_info - igsc info pointer
808 * ifp - interface pointer
810 * Return: SUCCESS or FAILURE
812 int32
813 igsc_interface_rtport_del(igsc_info_t *igsc_info, void *ifp)
815 clist_head_t *ptr, *tmp;
816 igsc_rtlist_t *rtl_ptr;
818 OSL_LOCK(igsc_info->rtlist_lock);
820 for (ptr = igsc_info->rtlist_head.next;
821 ptr != &igsc_info->rtlist_head; ptr = tmp)
823 rtl_ptr = clist_entry(ptr, igsc_rtlist_t, list);
825 tmp = ptr->next;
826 if (rtl_ptr->ifp == (igsc_rtlist_t *)ifp)
828 IGS_DEBUG("Router port entry %p found\n");
829 /* disable timer before remove rtport */
830 osl_timer_del(rtl_ptr->rtlist_timer);
831 emfc_rtport_del(igsc_info->emf_handle, rtl_ptr->ifp);
832 clist_delete(ptr);
833 MFREE(igsc_info->osh, rtl_ptr, sizeof(igsc_rtlist_t));
837 OSL_UNLOCK(igsc_info->rtlist_lock);
839 return SUCCESS;