Пример #1
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);
}
Пример #2
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);
}
Пример #3
0
/*
 * Description: This function is called by Netfilter when packet hits
 *              the ip post routing hook. The packet is sent to EMFL
 *              only when it is going on to bridge port.
 *
 * Input:       skb - Pointer to the packet buffer. Other parameters
 *                     are not used.
 *
 * Return:      Returns the value indicating packet can be forwarded
 *              or packet is stolen.
 */
static uint32
emf_ip_post_hook(uint32 hook, struct sk_buff *skb,
                 const struct net_device *in,
                 const struct net_device *out,
                 int32 (*okfn)(struct sk_buff *))
{
	emf_info_t *emfi;

	ASSERT(skb->protocol == __constant_htons(ETH_P_IP));

	EMF_DEBUG("Frame at IP_POST_HOOK going to if %p %s\n",
	          skb->dev, skb->dev->name);

	/* Find the LAN that the bridge interface corresponds to */
	emfi = emf_instance_find_by_brptr(emf, skb->dev);
	if (emfi == NULL)
	{
		EMF_INFO("No EMF processing needed for unknown ports\n");
		return (NF_ACCEPT);
	}

	EMF_DUMP_PKT(skb->data);

	return (emfc_input(emfi->emfci, skb, skb->dev,
	                   PKTDATA(NULL, skb), TRUE));
}
Пример #4
0
/*
 * Description: This function is called by Netfilter when packet hits
 *              the ip post routing hook. The packet is sent to EMFL
 *              only when it is going on to bridge port.
 *
 * Input:       pskb - Pointer to the packet buffer. Other parameters
 *                     are not used.
 *
 * Return:      Returns the value indicating packet can be forwarded
 *              or packet is stolen.
 */
static uint32
emf_ip_post_hook(
	uint32 hook,
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36)
	struct sk_buff *skb,
#else
	struct sk_buff **pskb,
#endif
	const struct net_device *in,
	const struct net_device *out,
	int32 (*okfn)(struct sk_buff *))
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36)
	struct sk_buff **pskb = &skb;
#endif
	emf_info_t *emfi;

	ASSERT((*pskb)->protocol == __constant_htons(ETH_P_IP));

	EMF_DEBUG("Frame at IP_POST_HOOK going to if %p %s\n",
	          (*pskb)->dev, (*pskb)->dev->name);

	/* Find the LAN that the bridge interface corresponds to */
	emfi = emf_instance_find_by_brptr(emf, (*pskb)->dev);
	if (emfi == NULL)
	{
		EMF_INFO("No EMF processing needed for unknown ports\n");
		return (NF_ACCEPT);
	}

	EMF_DUMP_PKT((*pskb)->data);

	return (emfc_input(emfi->emfci, *pskb, (*pskb)->dev,
	                   PKTDATA(NULL, *pskb), TRUE));
}
Пример #5
0
/*
 * Description: This function is called by EMFL common code when it wants
 *              to forward the packet on to a specific port. It adds the
 *              MAC header and queues the frame to the interface.
 *
 * Input:       emfi    - EMF instance information
 *              skb     - Pointer to the packet buffer.
 *              mgrp_ip - Multicast destination address.
 *              txif    - Interface to send the frame on.
 *
 * Return:      SUCCESS or FAILURE.
 */
int32
emf_forward(emf_info_t *emfi, struct sk_buff *skb, uint32 mgrp_ip,
            struct net_device *txif, bool rt_port)
{
	struct ether_header *eh;

	EMF_DEBUG("Forwarding the frame %p on to %s\n", skb, txif->name);

#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36)
	ASSERT(txif->br_port);
	/* Send only when the port is in forwarding state */
	if (EMF_BRPORT_STATE(txif) != BR_STATE_FORWARDING)
	{
		EMF_INFO("Dropping the frame as the port %s is not in"
		         " FORWARDING state\n", txif->name);
		kfree_skb(skb);
		return (FAILURE);
	}
	/* there is no access to the "bridge" struct from netif in 2.6.36 */
#endif
	eh = (struct ether_header *)skb_push(skb, ETH_HLEN);

	/* No need to fill the ether header fields for packets received
	 * from LAN ports.
	 */
	if (rt_port)
	{
		eh->ether_type = __constant_htons(ETH_P_IP);

		ETHER_FILL_MCAST_ADDR_FROM_IP(eh->ether_dhost, mgrp_ip);

		memcpy(eh->ether_shost, skb->dev->dev_addr, skb->dev->addr_len);
	}

	EMF_INFO("Group Addr: %02x:%02x:%02x:%02x:%02x:%02x\n",
	         eh->ether_dhost[0], eh->ether_dhost[1], eh->ether_dhost[2],
	         eh->ether_dhost[3], eh->ether_dhost[4], eh->ether_dhost[5]);

	/* Send buffer as if it is delivered by bridge */

#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22)
	skb_reset_mac_header(skb);
#else
	skb->mac.raw = skb->data;
#endif

	skb->dev = txif;
	dev_queue_xmit(skb);

	return (SUCCESS);
}
Пример #6
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;
}