Ejemplo n.º 1
0
int32
emf_iflist_list(emf_info_t *emfi, emf_cfg_if_list_t *list, uint32 size)
{
	int32 index = 0;
	emf_iflist_t *ptr;

	if (emfi == NULL)
	{
		EMF_ERROR("Invalid EMF instance handle passed\n");
		return (FAILURE);
	}

	if (list == NULL)
	{
		EMF_ERROR("Invalid buffer input\n");
		return (FAILURE);
	}

	for (ptr = emfi->iflist_head; ptr != NULL; ptr = ptr->next)
	{
		strncpy(list->if_entry[index++].if_name,
			ptr->if_ptr->name, 16);
	}

	/* Update the total number of entries */
	list->num_entries = index;

	return (SUCCESS);
}
Ejemplo n.º 2
0
/*
 * Description: This function is called during module load time. It
 *              opens communication channel to configure and start EMF.
 */
static int32 __init
emf_module_init(void)
{
	EMF_DEBUG("Loading EMF\n");

	/* Allocate EMF global data object */
	emf = MALLOC(NULL, sizeof(emf_struct_t));
	if (emf == NULL)
	{
		EMF_ERROR("Out of memory allocating emf_info\n");
		return (FAILURE);
	}

	memset(emf, 0, sizeof(emf_struct_t));

	/* Create a Netlink socket in kernel-space */
#define NETLINK_EMFC 17
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
	emf->nl_sk = netlink_kernel_create(NETLINK_EMFC, 0, emf_netlink_sock_cb,
	                                   NULL, THIS_MODULE);
#else
	emf->nl_sk = netlink_kernel_create(NETLINK_EMFC, emf_netlink_sock_cb);
#endif

	if (emf->nl_sk == NULL)
	{
		EMF_ERROR("Netlink kernel socket create failed\n");
		MFREE(NULL, emf, sizeof(emf_struct_t));
		return (FAILURE);
	}

	emf->lock = OSL_LOCK_CREATE("EMF Instance List");

	if (emf->lock == NULL)
	{
		EMF_ERROR("EMF instance list lock create failed\n");
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
		sock_release(emf->nl_sk->sk_socket);
#else
		sock_release(emf->nl_sk->socket);
#endif
		MFREE(NULL, emf, sizeof(emf_struct_t));
		return (FAILURE);
	}

	/* Call the common code global init function */
	if (emfc_module_init() != SUCCESS)
	{
		OSL_LOCK_DESTROY(emf->lock);
		MFREE(NULL, emf, sizeof(emf_struct_t));
		return (FAILURE);
	}

	EMF_DEBUG("EMF Init done\n");

	return (SUCCESS);
}
Ejemplo n.º 3
0
/*
 * EMFL Packet Counters/Statistics
 */
static int32
emf_stats_get(char *buf, char **start, off_t offset, int32 size,
              int32 *eof, void *data)
{
	emf_info_t *emfi = (emf_info_t *)data;
	emf_cfg_request_t *cfg;
	emf_stats_t *emfs;
	struct bcmstrbuf b;

	ASSERT(emfi);

	cfg = MALLOC(emfi->osh, sizeof(emf_cfg_request_t));
	if (cfg == NULL)
	{
		EMF_ERROR("Out of memory allocating emf_cfg_request\n");
		return (FAILURE);
	}

	cfg->command_id = EMFCFG_CMD_EMF_STATS;
	cfg->oper_type = EMFCFG_OPER_TYPE_GET;
	cfg->size = sizeof(emf_stats_t);
	emfs = (emf_stats_t *)cfg->arg;

	emfc_cfg_request_process(emfi->emfci, cfg);
	if (cfg->status != EMFCFG_STATUS_SUCCESS)
	{
		EMF_ERROR("Unable to get the EMF stats\n");
		MFREE(emfi->osh, cfg, sizeof(emf_cfg_request_t));
		return (FAILURE);
	}

	bcm_binit(&b, buf, size);
	bcm_bprintf(&b, "McastDataPkts   McastDataFwd    McastFlooded    "
		    "McastDataSentUp McastDataDropped\n");
	bcm_bprintf(&b, "%-15d %-15d %-15d %-15d %d\n",
	            emfs->mcast_data_frames, emfs->mcast_data_fwd,
	            emfs->mcast_data_flooded, emfs->mcast_data_sentup,
	            emfs->mcast_data_dropped);
	bcm_bprintf(&b, "IgmpPkts        IgmpPktsFwd     "
		    "IgmpPktsSentUp  MFDBCacheHits   MFDBCacheMisses\n");
	bcm_bprintf(&b, "%-15d %-15d %-15d %-15d %d\n",
	            emfs->igmp_frames, emfs->igmp_frames_fwd,
	            emfs->igmp_frames_sentup, emfs->mfdb_cache_hits,
	            emfs->mfdb_cache_misses);
	MFREE(emfi->osh, cfg, sizeof(emf_cfg_request_t));

	if (b.size == 0)
	{
		EMF_ERROR("Input buffer overflow\n");
		return (FAILURE);
	}

	return (b.buf - b.origbuf);
}
Ejemplo n.º 4
0
static int32
emf_mfdb_list(char *buf, char **start, off_t offset, int32 size,
              int32 *eof, void *data)
{
	emf_info_t *emfi = (emf_info_t *)data;
	emf_cfg_request_t *cfg;
	struct bcmstrbuf b;
	emf_cfg_mfdb_list_t *list;
	int32 i;

	ASSERT(emfi);

	cfg = MALLOC(emfi->osh, sizeof(emf_cfg_request_t));
	if (cfg == NULL)
	{
		EMF_ERROR("Out of memory allocating emf_cfg_request\n");
		return (FAILURE);
	}

	cfg->command_id = EMFCFG_CMD_MFDB_LIST;
	cfg->oper_type = EMFCFG_OPER_TYPE_GET;
	cfg->size = sizeof(cfg->arg);
	list = (emf_cfg_mfdb_list_t *)cfg->arg;

	emfc_cfg_request_process(emfi->emfci, cfg);
	if (cfg->status != EMFCFG_STATUS_SUCCESS)
	{
		EMF_ERROR("Unable to get the MFDB list\n");
		MFREE(emfi->osh, cfg, sizeof(emf_cfg_request_t));
		return (FAILURE);
	}

	bcm_binit(&b, buf, size);
	bcm_bprintf(&b, "Group           Interface      Pkts\n");

	for (i = 0; i < list->num_entries; i++)
	{
		bcm_bprintf(&b, "%08x        ", list->mfdb_entry[i].mgrp_ip);
		bcm_bprintf(&b, "%-15s", list->mfdb_entry[i].if_name);
		bcm_bprintf(&b, "%d\n", list->mfdb_entry[i].pkts_fwd);
	}
	MFREE(emfi->osh, cfg, sizeof(emf_cfg_request_t));

	if (b.size == 0)
	{
		EMF_ERROR("Input buffer overflow\n");
		return (FAILURE);
	}

	return (b.buf - b.origbuf);
}
Ejemplo n.º 5
0
/*
 * Description: This function is called by Linux kernel when user
 *              applications sends a message on netlink socket. It
 *              dequeues the message, calls the functions to process
 *              the commands and sends the result back to user.
 *
 * Input:       skb  - Kernel socket structure
 */
static void
emf_netlink_sock_cb(struct sk_buff *skb)
{
	struct nlmsghdr	*nlh;

	nlh = nlmsg_hdr(skb);
	EMF_DEBUG("Length of the command buffer %d\n", nlh->nlmsg_len);

	/* Check the buffer for min size */
	if (skb->len < NLMSG_SPACE(0) || skb->len < nlh->nlmsg_len ||
		nlh->nlmsg_len < NLMSG_LENGTH(sizeof(emf_cfg_request_t)))
	{
		EMF_ERROR("Configuration request size not > %d\n",
		          sizeof(emf_cfg_request_t));
		return;
	}

	skb = skb_clone(skb, GFP_KERNEL);
	if (skb == NULL)
		return;
	nlh = nlmsg_hdr(skb);

	/* Process the message */
	emf_cfg_request_process((emf_cfg_request_t *)NLMSG_DATA(nlh));

	/* Send the result to user process */
	NETLINK_CB(skb).pid = nlh->nlmsg_pid;
	NETLINK_CB(skb).dst_group = 0;

	netlink_unicast(emf->nl_sk, skb, nlh->nlmsg_pid, MSG_DONTWAIT);
}
Ejemplo n.º 6
0
int32
emf_hooks_register(emf_info_t *emfi)
{
	int32 i, ret, j;

	if (emf->hooks_reg)
		return (SUCCESS);

	/* Register at Netfilter bridge pre-routing and ip post-routing
	 * hooks to capture and process the packets.
	 */
	for (i = 0; i < sizeof(emf_nf_ops)/sizeof(struct nf_hook_ops); i++)
	{
		ret = nf_register_hook(&emf_nf_ops[i]);

		if (ret < 0)
		{
			EMF_ERROR("Unable to register netfilter hooks\n");
			for (j = 0; j < i; j++)
				nf_unregister_hook(&emf_nf_ops[j]);
			return (FAILURE);
		}
	}

	emf->hooks_reg++;

	return (SUCCESS);
}
Ejemplo n.º 7
0
static int32
emf_iflist_add(emf_struct_t *emf, emf_info_t *emfi, struct net_device *if_ptr)
{
	emf_iflist_t *ptr, *prev;

	OSL_LOCK(emf->lock);

	if (emf_iflist_find(emf, emfi, if_ptr, &prev) == NULL)
	{
		ptr = MALLOC(emfi->osh, sizeof(emf_iflist_t));

		if (ptr == NULL)
		{
			EMF_ERROR("Unable to allocate iflist entry\n");
			OSL_UNLOCK(emf->lock);
			return (FAILURE);
		}

		/* Initialize the iflist entry */
		ptr->if_ptr = if_ptr;

		/* Add the entry to iflist for this EMF instance */
		ptr->next = emfi->iflist_head;
		emfi->iflist_head = ptr;

		OSL_UNLOCK(emf->lock);
		return (SUCCESS);
	}

	OSL_UNLOCK(emf->lock);

	return (FAILURE);
}
Ejemplo n.º 8
0
/*
 * Description: This function is called when user disables EMF on a bridge
 *              interface. It unregisters the Netfilter hook functions,
 *              calls the common code cleanup routine and releases all the
 *              resources allocated during instance creation.
 *
 * Input:       emf      - EMF module global data pointer
 *              emf_info - EMF instance data pointer
 */
static int32
emf_instance_del(emf_struct_t *emf, emf_info_t *emfi)
{
	bool found = FALSE;
	osl_t *osh;
	emf_info_t *ptr, *prev;
#ifdef CONFIG_PROC_FS
	uint8 proc_name[64];
#endif /* CONFIG_PROC_FS */

	/* Interfaces attached to the EMF instance should be deleted first */
	emf_iflist_clear(emf, emfi);

	/* Delete the EMF instance */
	prev = NULL;
	for (ptr = emf->list_head; ptr != NULL; prev = ptr, ptr = ptr->next)
	{
		if (ptr == emfi)
		{
			found = TRUE;
			if (prev != NULL)
				prev->next = ptr->next;
			else
				emf->list_head = NULL;
			break;
		}
	}

	if (!found)
	{
		EMF_ERROR("EMF instance not found\n");
		return (FAILURE);
	}

	emf->inst_count--;

	/* Free the EMF instance */
	OSL_UNLOCK(emf->lock);
	emf_hooks_unregister(ptr);
	OSL_LOCK(emf->lock);
	emfc_exit(ptr->emfci);

#ifdef CONFIG_PROC_FS
	sprintf(proc_name, "net/emf_stats_%s", emfi->inst_id);
	remove_proc_entry(proc_name, 0);
	sprintf(proc_name, "net/emfdb_%s", emfi->inst_id);
	remove_proc_entry(proc_name, 0);
#endif /* CONFIG_PROC_FS */

	osh = ptr->osh;
	MFREE(emfi->osh, ptr, sizeof(emf_info_t));
	osl_detach(osh);

	return (SUCCESS);
}
Ejemplo n.º 9
0
/*
 * Description: This function is called by Linux kernel when user
 *              applications sends a message on netlink socket. It
 *              dequeues the message, calls the functions to process
 *              the commands and sends the result back to user.
 *
 * Input:       sk  - Kernel socket structure
 *              len - Length of the message received from user app.
 */
static void
emf_netlink_sock_cb(struct sock *sk, int32 len)
{
	struct sk_buff	*skb;
	struct nlmsghdr	*nlh = NULL;
	uint8 *data = NULL;

	EMF_DEBUG("Length of the command buffer %d\n", len);

	/* Dequeue the message from netlink socket */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
	while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL)
#else
	while ((skb = skb_dequeue(&sk->receive_queue)) != NULL)
#endif
	{
		/* Check the buffer for min size */
		if (skb->len < sizeof(emf_cfg_request_t))
		{
			EMF_ERROR("Configuration request size not > %d\n",
			          sizeof(emf_cfg_request_t));
			return;
		}

		/* Buffer contains netlink header followed by data */
		nlh = (struct nlmsghdr *)skb->data;
		data = NLMSG_DATA(nlh);

		/* Process the message */
		emf_cfg_request_process((emf_cfg_request_t *)data);

		/* Send the result to user process */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
		NETLINK_CB(skb).pid = nlh->nlmsg_pid;
		NETLINK_CB(skb).dst_group = 0;
#else
		NETLINK_CB(skb).groups = 0;
		NETLINK_CB(skb).pid = 0;
		NETLINK_CB(skb).dst_groups = 0;
		NETLINK_CB(skb).dst_pid = nlh->nlmsg_pid;
#endif

		netlink_unicast(emf->nl_sk, skb, nlh->nlmsg_pid, MSG_DONTWAIT);
	}

	return;
}
Ejemplo n.º 10
0
static void *
emf_if_name_validate(uint8 *if_name)
{
	struct net_device *dev;

	/* Get the interface pointer */
	dev = dev_get_by_name(if_name);

	if (dev == NULL)
	{
		EMF_ERROR("Interface %s doesn't exist\n", if_name);
		return (NULL);
	}

	dev_put(dev);

	return (dev);
}
Ejemplo n.º 11
0
void
emf_hooks_unregister(emf_info_t *emfi)
{
	int32 i;

	if (emf->hooks_reg == 0)
	{
		EMF_ERROR("Hooks already unregistered\n");
		return;
	}

	emf->hooks_reg--;

	/* Unregister all the hooks */
	for (i = 0; i < sizeof(emf_nf_ops)/sizeof(struct nf_hook_ops); i++)
	{
		nf_unregister_hook(&emf_nf_ops[i]);
	}

	return;
}
Ejemplo n.º 12
0
static void *
emf_if_name_validate(uint8 *if_name)
{
	struct net_device *dev;

	/* Get the interface pointer */

#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36)
	dev = dev_get_by_name(if_name);
#else
	dev = dev_get_by_name(&init_net, if_name);
#endif

	if (dev == NULL)
	{
		EMF_ERROR("Interface %s doesn't exist\n", if_name);
		return (NULL);
	}

	dev_put(dev);

	return (dev);
}
Ejemplo n.º 13
0
/*
 * Description: This function is called when the user application enables
 *              EMF on a bridge interface. It primarily allocates memory
 *              for instance data and calls the common code init function.
 *
 * Input:       emf     - EMF module global data pointer
 *              inst_id - EMF instance name
 *              br_ptr  - Bridge device pointer
 */
static emf_info_t *
emf_instance_add(emf_struct_t *emf, int8 *inst_id, struct net_device *br_ptr)
{
	emf_info_t *emfi;
	osl_t *osh;
#ifdef CONFIG_PROC_FS
	uint8 proc_name[64];
#endif /* CONFIG_PROC_FS */
	emfc_wrapper_t emfl;

	if (emf->inst_count > EMF_MAX_INST)
	{
		EMF_ERROR("Max instance limit %d exceeded\n", EMF_MAX_INST);
		return (NULL);
	}

	emf->inst_count++;

	EMF_INFO("Creating EMF instance for %s\n", inst_id);

	osh = osl_attach(NULL, PCI_BUS, FALSE);

	ASSERT(osh);

	/* Allocate os specfic EMF info object */
	emfi = MALLOC(osh, sizeof(emf_info_t));
	if (emfi == NULL)
	{
		EMF_ERROR("Out of memory allocating emf_info\n");
		osl_detach(osh);
		return (NULL);
	}

	emfi->osh = osh;

	/* Save the EMF instance identifier */
	strncpy(emfi->inst_id, inst_id, IFNAMSIZ);
	emfi->inst_id[IFNAMSIZ - 1] = 0;

	/* Save the device pointer */
	emfi->br_dev = br_ptr;

	/* Fill the linux wrapper specific functions */
	emfl.forward_fn = (forward_fn_ptr)emf_forward;
	emfl.sendup_fn = (sendup_fn_ptr)emf_sendup;
	emfl.hooks_register_fn = (hooks_register_fn_ptr)emf_hooks_register;
	emfl.hooks_unregister_fn = (hooks_unregister_fn_ptr)emf_hooks_unregister;

	/* Initialize EMFC instance */
	if ((emfi->emfci = emfc_init(inst_id, (void *)emfi, osh, &emfl)) == NULL)
	{
		EMF_ERROR("EMFC init failed\n");
		MFREE(osh, emfi, sizeof(emf_info_t));
		osl_detach(osh);
		return (NULL);
	}

	EMF_INFO("Created EMFC instance for %s\n", inst_id);

	/* Initialize the iflist head */
	emfi->iflist_head = NULL;

#ifdef CONFIG_PROC_FS
	sprintf(proc_name, "net/emf_stats_%s", inst_id);
	create_proc_read_entry(proc_name, 0, 0, emf_stats_get, emfi);
	sprintf(proc_name, "net/emfdb_%s", inst_id);
	create_proc_read_entry(proc_name, 0, 0, emf_mfdb_list, emfi);
#endif /* CONFIG_PROC_FS */

	/* Add to the global EMF instance list */
	emfi->next = emf->list_head;
	emf->list_head = emfi;

	return (emfi);
}