| /* |
| ************************************************************************** |
| * Copyright (c) 2017 The Linux Foundation. All rights reserved. |
| * Permission to use, copy, modify, and/or distribute this software for |
| * any purpose with or without fee is hereby granted, provided that the |
| * above copyright notice and this permission notice appear in all copies. |
| * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
| * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
| * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
| * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
| * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
| * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT |
| * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
| ************************************************************************** |
| */ |
| |
| /* |
| * nss_connnmgr_gre_test.c |
| * test module implementation |
| */ |
| |
| #include <linux/version.h> |
| #include <linux/types.h> |
| #include <linux/module.h> |
| #include <linux/netdevice.h> |
| #include <linux/inet.h> |
| #include <net/ipv6.h> |
| #include <net/ip6_tunnel.h> |
| #include <net/ip_tunnels.h> |
| #include <linux/proc_fs.h> |
| #include <linux/slab.h> |
| |
| #include <nss_api_if.h> |
| |
| #include "nss_connmgr_gre_public.h" |
| #include "nss_connmgr_gre.h" |
| |
| #define MAX_PROC_SIZE 1024 |
| static struct proc_dir_entry *proc_entry; |
| |
| /* |
| * nss_connmgr_gre_test() |
| * Function calls API (exported by client code) to create GRE tap interface |
| * and destroy interface based on command writter to /proc/gre entry. |
| */ |
| static int nss_connmgr_gre_test(char *src_ip, char *dest_ip, char *next_dev_name) |
| { |
| int ret = -1; |
| uint32_t sip, dip; |
| struct nss_connmgr_gre_cfg cfg; |
| struct net_device *dev, *next_dev; |
| enum nss_connmgr_gre_err_codes err_code; |
| |
| ret = in4_pton(src_ip, -1, (uint8_t *)&sip, -1, NULL); |
| if (ret != 1) { |
| pr_err("Not a valid src ip\n"); |
| return -1; |
| } |
| |
| ret = in4_pton(dest_ip, -1, (uint8_t *)&dip, -1, NULL); |
| if (ret != 1) { |
| pr_err("Not a valid dest ip\n"); |
| return -1; |
| } |
| |
| sip = ntohl(sip); |
| dip = ntohl(dip); |
| |
| if (!next_dev_name) { |
| pr_err("next_dev=%s is not a valid param", next_dev_name); |
| return -1; |
| } |
| |
| next_dev = dev_get_by_name(&init_net, next_dev_name); |
| if (!next_dev) { |
| pr_err("next_dev=%s is not a valid param", next_dev_name); |
| return -1; |
| } |
| |
| memset(&cfg, 0, sizeof(struct nss_connmgr_gre_cfg)); |
| |
| cfg.mode = GRE_MODE_TAP; |
| cfg.ip_type = GRE_OVER_IPV4; |
| cfg.ttl_inherit = true; |
| cfg.tos_inherit = true; |
| cfg.add_padding = false; |
| cfg.copy_metadata = true; |
| cfg.next_dev = next_dev; |
| |
| cfg.src_ip[0] = sip; |
| cfg.dest_ip[0] = dip; |
| |
| dev = nss_connmgr_gre_create_interface(&cfg, &err_code); |
| dev_put(next_dev); |
| if (!dev) { |
| pr_err("Could not create gre interface, err=%d\n", err_code); |
| return -1; |
| } |
| |
| pr_info("Gre interface %s created\n", dev->name); |
| return 0; |
| } |
| |
| /* |
| * nss_connmgr_gre_test_write_proc() |
| * Write call back for proc entry. |
| */ |
| static ssize_t nss_connmgr_gre_test_write_proc(struct file *file, const char __user *buf, size_t count, loff_t *offset) |
| { |
| char *token; |
| struct net_device *dev; |
| char saddr[20] = {0}, daddr[20] = {0}, dev_name[IFNAMSIZ] = {0}; |
| bool saddr_valid = false, daddr_valid = false, dev_name_valid = false; |
| char *buffer = kzalloc(MAX_PROC_SIZE, GFP_KERNEL); |
| char *pfree; |
| int ret; |
| |
| if (!buffer) { |
| return -ENOMEM; |
| } |
| pfree = buffer; |
| |
| if (count > MAX_PROC_SIZE) { |
| count = MAX_PROC_SIZE; |
| } |
| |
| if (copy_from_user(buffer, buf, count)) { |
| kfree(pfree); |
| return -EFAULT; |
| } |
| |
| while (buffer) { |
| char *param, *value; |
| token = strsep(&buffer, " \n"); |
| if (token[0] == 0) { |
| continue; |
| } |
| |
| param = strsep(&token, "="); |
| value = token; |
| |
| /* |
| * parameter parsing for delete command |
| */ |
| if (!strcmp(param, "dev")) { |
| strlcpy(dev_name, value, IFNAMSIZ); |
| dev_name_valid = true; |
| break; |
| } |
| |
| /* |
| * Parse next_dev, src ip and dest ip for GRE |
| * tap create command |
| */ |
| if (!strcmp(param, "next_dev")) { |
| strlcpy(dev_name, value, IFNAMSIZ); |
| dev_name_valid = true; |
| continue; |
| } |
| |
| if (!strcmp(param, "saddr")) { |
| strlcpy(saddr, value, 20); |
| saddr_valid = true; |
| continue; |
| } |
| |
| if (!strcmp(param, "daddr")) { |
| strlcpy(daddr, value, 20); |
| daddr_valid = true; |
| continue; |
| } |
| |
| } |
| |
| kfree(pfree); |
| |
| if (dev_name_valid && !saddr_valid && !daddr_valid) { |
| dev = dev_get_by_name(&init_net, dev_name); |
| if (!dev) { |
| pr_err("Invalid arguments\n"); |
| return -EINVAL; |
| } |
| dev_put(dev); |
| |
| ret = nss_connmgr_gre_destroy_interface(dev); |
| if (ret) { |
| pr_err("Could not delete interface, failed with errcode=%d\n", ret); |
| return -EINVAL; |
| } |
| |
| pr_info("Sucessfully deleted %s interface\n", dev_name); |
| return count; |
| } |
| |
| if (!(dev_name_valid && saddr_valid && daddr_valid)) { |
| pr_err("Invalid arguments\n"); |
| return -EINVAL; |
| } |
| |
| if (nss_connmgr_gre_test(saddr, daddr, dev_name)) { |
| return -EFAULT; |
| } |
| |
| return count; |
| } |
| |
| /* |
| * nss_connmgr_gre_test_show_proc() |
| * Displays help text on how to use this module. |
| */ |
| static int nss_connmgr_gre_test_show_proc(struct seq_file *filp, void *data) |
| { |
| seq_printf(filp, "Help:\n** Create interface **\n"); |
| seq_printf(filp, "echo \"saddr=192.168.10.1 daddr=192.168.10.100 next_dev=ath0\" > /proc/gre\n\n"); |
| seq_printf(filp, "\n** Delete interface **\n"); |
| seq_printf(filp, "echo \"dev=tap-0\" > /proc/gre\n\n"); |
| return 0; |
| } |
| |
| /* |
| * nss_connmgr_gre_test_open_proc() |
| * Open call back for proc entry. |
| */ |
| static int nss_connmgr_gre_test_open_proc(struct inode *inode, struct file *filp) |
| { |
| return single_open(filp, nss_connmgr_gre_test_show_proc, PDE_DATA(inode)); |
| } |
| |
| /* |
| * Proc ops |
| */ |
| static const struct file_operations nss_connmgr_gre_test_proc_ops = { |
| .open = nss_connmgr_gre_test_open_proc, |
| .write = nss_connmgr_gre_test_write_proc, |
| .read = seq_read, |
| }; |
| |
| /* |
| * nss_connmgr_gre_test_init_module() |
| * Test module init function. |
| */ |
| static int __init nss_connmgr_gre_test_init_module(void) |
| { |
| proc_entry = proc_create_data("gre", S_IWUGO, NULL, |
| &nss_connmgr_gre_test_proc_ops, |
| NULL); |
| |
| if (!proc_entry) { |
| pr_err("Creation of proc entry faild\n"); |
| return -1; |
| } |
| |
| pr_info("Read Help: cat /proc/gre\n"); |
| return 0; |
| } |
| |
| /* |
| * nss_connmgr_gre_test_exit_module |
| * Test module exit function |
| */ |
| static void __exit nss_connmgr_gre_test_exit_module(void) |
| { |
| proc_remove(proc_entry); |
| } |
| |
| module_init(nss_connmgr_gre_test_init_module); |
| module_exit(nss_connmgr_gre_test_exit_module); |
| |
| MODULE_LICENSE("Dual BSD/GPL"); |
| MODULE_DESCRIPTION("NSS gre test module"); |