Update primary code license to Apache 2.0.
[cascardo/ovs.git] / datapath / brc_procfs.c
1 /*
2  * Copyright (c) 2009 Nicira Networks.
3  * Distributed under the terms of the GNU GPL version 2.
4  *
5  * Significant portions of this file may be copied from parts of the Linux
6  * kernel, by Linus Torvalds and others.
7  */
8
9 #include <linux/kernel.h>
10 #include <linux/module.h>
11 #include <linux/netdevice.h>
12 #include <linux/proc_fs.h>
13 #include <linux/seq_file.h>
14 #include <net/genetlink.h>
15 #include "openvswitch/brcompat-netlink.h"
16
17 /* This code implements a Generic Netlink command BRC_GENL_C_SET_PROC that can
18  * be used to add, modify, and delete arbitrary files in selected
19  * subdirectories of /proc.  It's a horrible kluge prompted by the need to
20  * simulate certain /proc/net/vlan and /proc/net/bonding files for software
21  * that wants to read them, and with any luck it will go away eventually.
22  *
23  * The implementation is a kluge too.  In particular, we want to release the
24  * strings copied into the 'data' members of proc_dir_entry when the
25  * proc_dir_entry structures are freed, but there doesn't appear to be a way to
26  * hook that, so instead we have to rely on being the only entity modifying the
27  * directories in question.
28  */
29
30 static int brc_seq_show(struct seq_file *seq, void *unused)
31 {
32         seq_puts(seq, seq->private);
33         return 0;
34 }
35
36 static int brc_seq_open(struct inode *inode, struct file *file)
37 {
38         return single_open(file, brc_seq_show, PDE(inode)->data);
39 }
40
41 static struct file_operations brc_fops = {
42         .owner = THIS_MODULE,
43         .open    = brc_seq_open,
44         .read    = seq_read,
45         .llseek  = seq_lseek,
46         .release = single_release,
47 };
48
49 static struct proc_dir_entry *proc_vlan_dir;
50 static struct proc_dir_entry *proc_bonding_dir;
51
52 struct proc_dir_entry *brc_lookup_entry(struct proc_dir_entry *de, const char *name)
53 {
54         int namelen = strlen(name);
55         for (de = de->subdir; de; de = de->next) {
56                 if (de->namelen != namelen)
57                         continue;
58                 if (!memcmp(name, de->name, de->namelen))
59                         return de;
60         }
61         return NULL;
62 }
63
64 static struct proc_dir_entry *brc_open_dir(const char *dir_name,
65                                            struct proc_dir_entry *parent,
66                                            struct proc_dir_entry **dirp)
67 {
68         if (!*dirp) {
69                 struct proc_dir_entry *dir;
70                 if (brc_lookup_entry(parent, dir_name)) {
71                         printk(KERN_WARNING "%s proc directory exists, can't "
72                                "simulate--probably its real module is "
73                                "loaded\n", dir_name);
74                         return NULL;
75                 }
76                 dir = *dirp = proc_mkdir(dir_name, parent);
77         }
78         return *dirp;
79 }
80
81 /* Maximum length of the BRC_GENL_A_PROC_DIR and BRC_GENL_A_PROC_NAME strings.
82  * If we could depend on supporting NLA_NUL_STRING and the .len member in
83  * Generic Netlink policy, then we could just put this in brc_genl_policy (and
84  * simplify brc_genl_set_proc() below too), but upstream 2.6.18 does not have
85  * either. */
86 #define BRC_NAME_LEN_MAX 32
87
88 int brc_genl_set_proc(struct sk_buff *skb, struct genl_info *info)
89 {
90         struct proc_dir_entry *dir, *entry;
91         const char *dir_name, *name;
92         char *data;
93
94         if (!info->attrs[BRC_GENL_A_PROC_DIR] ||
95             VERIFY_NUL_STRING(info->attrs[BRC_GENL_A_PROC_DIR]) ||
96             !info->attrs[BRC_GENL_A_PROC_NAME] ||
97             VERIFY_NUL_STRING(info->attrs[BRC_GENL_A_PROC_NAME]) ||
98             (info->attrs[BRC_GENL_A_PROC_DATA] &&
99              VERIFY_NUL_STRING(info->attrs[BRC_GENL_A_PROC_DATA])))
100                 return -EINVAL;
101
102         dir_name = nla_data(info->attrs[BRC_GENL_A_PROC_DIR]);
103         name = nla_data(info->attrs[BRC_GENL_A_PROC_NAME]);
104         if (strlen(dir_name) > BRC_NAME_LEN_MAX ||
105             strlen(name) > BRC_NAME_LEN_MAX)
106                 return -EINVAL;
107
108         if (!strcmp(dir_name, "net/vlan"))
109                 dir = brc_open_dir("vlan", proc_net, &proc_vlan_dir);
110         else if (!strcmp(dir_name, "net/bonding"))
111                 dir = brc_open_dir("bonding", proc_net, &proc_bonding_dir);
112         else
113                 return -EINVAL;
114         if (!dir) {
115                 /* Probably failed because the module that really implements
116                  * the function in question is loaded and already owns the
117                  * directory in question.*/
118                 return -EBUSY;
119         }
120
121         entry = brc_lookup_entry(dir, name);
122         if (!info->attrs[BRC_GENL_A_PROC_DATA]) {
123                 if (!entry)
124                         return -ENOENT;
125
126                 data = entry->data;
127                 remove_proc_entry(name, dir);
128                 if (brc_lookup_entry(dir, name))
129                         return -EBUSY; /* Shouldn't happen */
130
131                 kfree(data);
132         } else {
133                 data = kstrdup(nla_data(info->attrs[BRC_GENL_A_PROC_DATA]),
134                                GFP_KERNEL);
135                 if (!data)
136                         return -ENOMEM;
137
138                 if (entry) {
139                         char *old_data = entry->data;
140                         entry->data = data;
141                         kfree(old_data);
142                         return 0;
143                 }
144
145                 entry = create_proc_entry(name, S_IFREG|S_IRUSR|S_IWUSR, dir);
146                 if (!entry) {
147                         kfree(data);
148                         return -ENOBUFS;
149                 }
150                 entry->proc_fops = &brc_fops;
151                 entry->data = data;
152         }
153         return 0;
154 }
155
156 static void kill_proc_dir(const char *dir_name,
157                           struct proc_dir_entry *parent,
158                           struct proc_dir_entry *dir)
159 {
160         if (!dir)
161                 return;
162         for (;;) {
163                 struct proc_dir_entry *e;
164                 char *data;
165                 char name[BRC_NAME_LEN_MAX + 1];
166
167                 e = dir->subdir;
168                 if (!e)
169                         break;
170
171                 if (e->namelen >= sizeof name) {
172                         /* Can't happen: we prevent adding names this long by
173                          * limiting the BRC_GENL_A_PROC_NAME string to
174                          * BRC_NAME_LEN_MAX bytes.  */
175                         WARN_ON(1);
176                         break;
177                 }
178                 strcpy(name, e->name);
179
180                 data = e->data;
181                 e->data = NULL;
182                 kfree(data);
183
184                 remove_proc_entry(name, dir);
185         }
186         remove_proc_entry(dir_name, parent);
187 }
188
189 void brc_procfs_exit(void)
190 {
191         kill_proc_dir("vlan", proc_net, proc_vlan_dir);
192         kill_proc_dir("bonding", proc_net, proc_bonding_dir);
193 }