/* * 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); }
/* * 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); }
/* * 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)); }
/* * 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)); }
/* * 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); }
/* * 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; }