2 * Copyright (c) 2009, 2010, 2011 Nicira Networks.
3 * Distributed under the terms of the GNU GPL version 2.
5 * Significant portions of this file may be copied from parts of the Linux
6 * kernel, by Linus Torvalds and others.
9 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
11 #include <linux/kernel.h>
12 #include <linux/module.h>
13 #include <linux/netdevice.h>
14 #include <linux/proc_fs.h>
15 #include <linux/seq_file.h>
16 #include <net/genetlink.h>
17 #include "brc_procfs.h"
18 #include "openvswitch/brcompat-netlink.h"
20 /* This code implements a Generic Netlink command BRC_GENL_C_SET_PROC that can
21 * be used to add, modify, and delete arbitrary files in selected
22 * subdirectories of /proc. It's a horrible kluge prompted by the need to
23 * simulate certain /proc/net/vlan and /proc/net/bonding files for software
24 * that wants to read them, and with any luck it will go away eventually.
26 * The implementation is a kluge too. In particular, we want to release the
27 * strings copied into the 'data' members of proc_dir_entry when the
28 * proc_dir_entry structures are freed, but there doesn't appear to be a way to
29 * hook that, so instead we have to rely on being the only entity modifying the
30 * directories in question.
33 static int brc_seq_show(struct seq_file *seq, void *unused)
35 seq_puts(seq, seq->private);
39 static int brc_seq_open(struct inode *inode, struct file *file)
41 return single_open(file, brc_seq_show, PDE(inode)->data);
44 static struct file_operations brc_fops = {
49 .release = single_release,
52 static struct proc_dir_entry *proc_vlan_dir;
53 static struct proc_dir_entry *proc_bonding_dir;
55 static struct proc_dir_entry *brc_lookup_entry(struct proc_dir_entry *de, const char *name)
57 int namelen = strlen(name);
58 for (de = de->subdir; de; de = de->next) {
59 if (de->namelen != namelen)
61 if (!memcmp(name, de->name, de->namelen))
67 static struct proc_dir_entry *brc_open_dir(const char *dir_name,
68 struct proc_dir_entry *parent,
69 struct proc_dir_entry **dirp)
72 struct proc_dir_entry *dir;
73 if (brc_lookup_entry(parent, dir_name)) {
74 pr_warn("%s proc directory exists, can't simulate--"
75 "probably its real module is loaded\n",
79 dir = *dirp = proc_mkdir(dir_name, parent);
84 int brc_genl_set_proc(struct sk_buff *skb, struct genl_info *info)
86 struct proc_dir_entry *dir, *entry;
87 const char *dir_name, *name;
90 if (!info->attrs[BRC_GENL_A_PROC_DIR] ||
91 VERIFY_NUL_STRING(info->attrs[BRC_GENL_A_PROC_DIR], BRC_NAME_LEN_MAX) ||
92 !info->attrs[BRC_GENL_A_PROC_NAME] ||
93 VERIFY_NUL_STRING(info->attrs[BRC_GENL_A_PROC_NAME], BRC_NAME_LEN_MAX) ||
94 (info->attrs[BRC_GENL_A_PROC_DATA] &&
95 VERIFY_NUL_STRING(info->attrs[BRC_GENL_A_PROC_DATA], INT_MAX)))
98 dir_name = nla_data(info->attrs[BRC_GENL_A_PROC_DIR]);
99 name = nla_data(info->attrs[BRC_GENL_A_PROC_NAME]);
101 if (!strcmp(dir_name, "net/vlan"))
102 dir = brc_open_dir("vlan", proc_net, &proc_vlan_dir);
103 else if (!strcmp(dir_name, "net/bonding"))
104 dir = brc_open_dir("bonding", proc_net, &proc_bonding_dir);
108 /* Probably failed because the module that really implements
109 * the function in question is loaded and already owns the
110 * directory in question.*/
114 entry = brc_lookup_entry(dir, name);
115 if (!info->attrs[BRC_GENL_A_PROC_DATA]) {
120 remove_proc_entry(name, dir);
121 if (brc_lookup_entry(dir, name))
122 return -EBUSY; /* Shouldn't happen */
126 data = kstrdup(nla_data(info->attrs[BRC_GENL_A_PROC_DATA]),
132 char *old_data = entry->data;
138 entry = create_proc_entry(name, S_IFREG|S_IRUSR|S_IWUSR, dir);
143 entry->proc_fops = &brc_fops;
149 static void kill_proc_dir(const char *dir_name,
150 struct proc_dir_entry *parent,
151 struct proc_dir_entry *dir)
156 struct proc_dir_entry *e;
158 char name[BRC_NAME_LEN_MAX + 1];
164 if (e->namelen >= sizeof(name)) {
165 /* Can't happen: we prevent adding names this long by
166 * limiting the BRC_GENL_A_PROC_NAME string to
167 * BRC_NAME_LEN_MAX bytes. */
171 strcpy(name, e->name);
177 remove_proc_entry(name, dir);
179 remove_proc_entry(dir_name, parent);
182 void brc_procfs_exit(void)
184 kill_proc_dir("vlan", proc_net, proc_vlan_dir);
185 kill_proc_dir("bonding", proc_net, proc_bonding_dir);