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