1 #include <linux/kernel.h>
2 #include <linux/module.h>
3 #include <linux/netdevice.h>
4 #include <linux/proc_fs.h>
5 #include <linux/seq_file.h>
6 #include <net/genetlink.h>
7 #include "openvswitch/brcompat-netlink.h"
9 /* This code implements a Generic Netlink command BRC_GENL_C_SET_PROC that can
10 * be used to add, modify, and delete arbitrary files in selected
11 * subdirectories of /proc. It's a horrible kluge prompted by the need to
12 * simulate certain /proc/net/vlan and /proc/net/bonding files for software
13 * that wants to read them, and with any luck it will go away eventually.
15 * The implementation is a kluge too. In particular, we want to release the
16 * strings copied into the 'data' members of proc_dir_entry when the
17 * proc_dir_entry structures are freed, but there doesn't appear to be a way to
18 * hook that, so instead we have to rely on being the only entity modifying the
19 * directories in question.
22 static int brc_seq_show(struct seq_file *seq, void *unused)
24 seq_puts(seq, seq->private);
28 static int brc_seq_open(struct inode *inode, struct file *file)
30 return single_open(file, brc_seq_show, PDE(inode)->data);
33 static struct file_operations brc_fops = {
38 .release = single_release,
41 static struct proc_dir_entry *proc_vlan_dir;
42 static struct proc_dir_entry *proc_bonding_dir;
44 struct proc_dir_entry *brc_lookup_entry(struct proc_dir_entry *de, const char *name)
46 int namelen = strlen(name);
47 for (de = de->subdir; de; de = de->next) {
48 if (de->namelen != namelen)
50 if (!memcmp(name, de->name, de->namelen))
56 static struct proc_dir_entry *brc_open_dir(const char *dir_name,
57 struct proc_dir_entry *parent,
58 struct proc_dir_entry **dirp)
61 struct proc_dir_entry *dir;
62 if (brc_lookup_entry(parent, dir_name)) {
63 printk(KERN_WARNING "%s proc directory exists, can't "
64 "simulate--probably its real module is "
65 "loaded\n", dir_name);
68 dir = *dirp = proc_mkdir(dir_name, parent);
73 /* Maximum length of the BRC_GENL_A_PROC_DIR and BRC_GENL_A_PROC_NAME strings.
74 * If we could depend on supporting NLA_NUL_STRING and the .len member in
75 * Generic Netlink policy, then we could just put this in brc_genl_policy (and
76 * simplify brc_genl_set_proc() below too), but upstream 2.6.18 does not have
78 #define BRC_NAME_LEN_MAX 32
80 int brc_genl_set_proc(struct sk_buff *skb, struct genl_info *info)
82 struct proc_dir_entry *dir, *entry;
83 const char *dir_name, *name;
86 if (!info->attrs[BRC_GENL_A_PROC_DIR] ||
87 VERIFY_NUL_STRING(info->attrs[BRC_GENL_A_PROC_DIR]) ||
88 !info->attrs[BRC_GENL_A_PROC_NAME] ||
89 VERIFY_NUL_STRING(info->attrs[BRC_GENL_A_PROC_NAME]) ||
90 (info->attrs[BRC_GENL_A_PROC_DATA] &&
91 VERIFY_NUL_STRING(info->attrs[BRC_GENL_A_PROC_DATA])))
94 dir_name = nla_data(info->attrs[BRC_GENL_A_PROC_DIR]);
95 name = nla_data(info->attrs[BRC_GENL_A_PROC_NAME]);
96 if (strlen(dir_name) > BRC_NAME_LEN_MAX ||
97 strlen(name) > BRC_NAME_LEN_MAX)
100 if (!strcmp(dir_name, "net/vlan"))
101 dir = brc_open_dir("vlan", proc_net, &proc_vlan_dir);
102 else if (!strcmp(dir_name, "net/bonding"))
103 dir = brc_open_dir("bonding", proc_net, &proc_bonding_dir);
107 /* Probably failed because the module that really implements
108 * the function in question is loaded and already owns the
109 * directory in question.*/
113 entry = brc_lookup_entry(dir, name);
114 if (!info->attrs[BRC_GENL_A_PROC_DATA]) {
119 remove_proc_entry(name, dir);
120 if (brc_lookup_entry(dir, name))
121 return -EBUSY; /* Shouldn't happen */
125 data = kstrdup(nla_data(info->attrs[BRC_GENL_A_PROC_DATA]),
131 char *old_data = entry->data;
137 entry = create_proc_entry(name, S_IFREG|S_IRUSR|S_IWUSR, dir);
142 entry->proc_fops = &brc_fops;
148 static void kill_proc_dir(const char *dir_name,
149 struct proc_dir_entry *parent,
150 struct proc_dir_entry *dir)
155 struct proc_dir_entry *e;
157 char name[BRC_NAME_LEN_MAX + 1];
163 if (e->namelen >= sizeof name) {
164 /* Can't happen: we prevent adding names this long by
165 * limiting the BRC_GENL_A_PROC_NAME string to
166 * BRC_NAME_LEN_MAX bytes. */
170 strcpy(name, e->name);
176 remove_proc_entry(name, dir);
178 remove_proc_entry(dir_name, parent);
181 void brc_procfs_exit(void)
183 kill_proc_dir("vlan", proc_net, proc_vlan_dir);
184 kill_proc_dir("bonding", proc_net, proc_bonding_dir);