debuggers.hg

view tools/vnet/vnet-module/vnet_ioctl.c @ 0:7d21f7218375

Exact replica of unstable on 051908 + README-this
author Mukesh Rathor
date Mon May 19 15:34:57 2008 -0700 (2008-05-19)
parents
children
line source
1 /*
2 * Copyright (C) 2004, 2005 Mike Wray <mike.wray@hp.com>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * for more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free software Foundation, Inc.,
16 * 59 Temple Place, suite 330, Boston, MA 02111-1307 USA
17 *
18 */
19 #include <linux/config.h>
20 #include <linux/module.h>
22 #include <linux/types.h>
23 #include <linux/kernel.h>
24 #include <linux/errno.h>
26 #include <asm/uaccess.h>
28 #include <linux/slab.h>
30 #include <linux/proc_fs.h>
31 #include <linux/string.h>
33 #include <linux/net.h>
34 #include <linux/in.h>
35 #include <linux/inet.h>
36 #include <linux/netdevice.h>
38 #include <sa.h>
39 #include "vif.h"
40 #include "vnet.h"
41 #include "varp.h"
42 #include "vnet_dev.h"
43 #include "vnet_eval.h"
44 #include "vnet_forward.h"
46 #include "iostream.h"
47 #include "kernel_stream.h"
48 #include "mem_stream.h"
49 #include "sys_string.h"
50 #include "sys_net.h"
51 #include "sxpr_parser.h"
53 #define MODULE_NAME "VNET"
54 #define DEBUG 1
55 #undef DEBUG
56 #include "debug.h"
58 /** @file
59 *
60 * Kernel interface to files in /proc.
61 * todo: Add a sysfs interface using kobject.
62 */
64 #define PROC_ROOT "/proc/"
65 #define PROC_ROOT_LEN 6
66 #define MODULE_ROOT PROC_ROOT "vnet"
68 enum {
69 VNET_POLICY = 1,
70 VNET_VNETS,
71 VNET_VIFS,
72 VNET_VARP,
73 VNET_PEERS,
74 };
76 typedef struct proc_dir_entry ProcEntry;
77 typedef struct inode Inode;
78 typedef struct file File;
80 static int proc_open_fn(struct inode *inode, File *file);
81 //static ssize_t proc_read_fn(File *file, char *buffer, size_t count, loff_t *offset);
82 //static ssize_t proc_write_fn(File *file, const char *buffer, size_t count, loff_t *offset) ;
83 //static int proc_flush_fn(File *file);
84 static loff_t proc_lseek_fn(File * file, loff_t offset, int orig);
85 static int proc_ioctl_fn(struct inode *inode, File *file, unsigned opcode, unsigned long arg);
86 //static int proc_release_fn(struct inode *inode, File *file);
88 static int ProcEntry_has_name(ProcEntry *entry, const char *name, int namelen){
89 dprintf("> name=%.*s entry=%.*s\n", namelen, name, entry->namelen, entry->name);
90 if(!entry || !entry->low_ino) return FALSE;
91 if(entry->namelen != namelen) return FALSE;
92 return memcmp(name, entry->name, namelen) == 0;
93 }
95 // Set f->f_error on error?
96 // Does interface stop r/w on first error?
97 // Is release called after an error?
98 //
100 static int proc_get_parser(File *file, Parser **val){
101 int err = 0;
102 Parser *parser = NULL;
103 parser = file->private_data;
104 if(!parser){
105 parser = Parser_new();
106 if(!parser){
107 err = -ENOMEM;
108 goto exit;
109 }
110 file->private_data = parser;
111 }
112 exit:
113 *val = parser;
114 return err;
115 }
117 static int proc_open_fn(Inode *inode, File *file){
118 // User open.
119 // Return errcode or 0 on success.
120 // Can stuff data in file->private_data (void*).
121 // Get entry from
122 //ProcEntry *entry = (ProcEntry *)inode->u.generic_ip;
123 //file->private_data = NULL;
124 //file->f_dentry->d_ino is inode.
125 // Check for user privilege - deny otherwise.
126 // -EACCESS
127 int err = 0;
128 dprintf(">\n");
129 file->private_data = NULL;
130 return err;
131 }
133 static ssize_t proc_read_fn(File *file, char *buffer,
134 size_t count, loff_t *offset){
135 // User read.
136 // Copy data to user buffer, increment offset by count, return count.
137 dprintf(">\n");
138 count = 0;
139 //if(copy_to_user(buffer, data, count)){
140 // return -EFAULT;
141 //}
142 //*offset += count;
143 return count;
144 }
146 #if 0
147 static ssize_t proc_write_fn(File *file, const char *buffer,
148 size_t count, loff_t *offset) {
149 return -EINVAL;
150 }
151 #endif
154 #if 0
155 static int proc_flush_fn(File *file){
156 // User flush.
157 int writing = (file->f_flags & O_ACCMODE) == O_WRONLY;
158 int f_count = atomic_read(&file->f_count);
159 if (writing && f_count == 1) {
160 ProcEntry *pentry = (ProcEntry *)file->f_dentry->d_inode->u.generic_ip;
161 // ...
162 }
163 return retval;
164 }
165 #endif
167 #ifndef SEEK_SET
168 enum {
169 /** Offset from start. */
170 SEEK_SET = 0,
171 /** Offset from current position. */
172 SEEK_CUR = 1,
173 /** Offset from size of file. */
174 SEEK_END = 2
175 };
176 #endif /* !SEEK_SET */
178 static loff_t proc_lseek_fn(File * file, loff_t offset, int from){
179 // User lseek.
180 dprintf(">\n");
181 switch(from){
182 case SEEK_SET:
183 break;
184 case SEEK_CUR:
185 offset += file->f_pos;
186 break;
187 case SEEK_END:
188 return -EINVAL;
189 default:
190 return -EINVAL;
191 }
192 if(offset < 0) return -EINVAL;
193 file->f_pos = offset;
194 return offset;
195 }
197 static int proc_ioctl_fn(Inode *inode, File *file,
198 unsigned opcode, unsigned long arg){
199 // User ioctl.
200 dprintf(">\n");
201 return 0;
202 }
204 static ssize_t proc_policy_write_fn(File *file, const char *buffer,
205 size_t count, loff_t *offset) {
206 // User write.
207 // Copy data into kernel space from buffer.
208 // Increment offset by count, return count (or code).
209 int err = 0;
210 char *data = NULL;
211 Parser *parser = NULL;
213 err = proc_get_parser(file, &parser);
214 if(err) goto exit;
215 data = allocate(count);
216 if(!data){
217 err = -ENOMEM;
218 goto exit;
219 }
220 err = copy_from_user(data, buffer, count);
221 if(err) goto exit;
222 *offset += count;
223 err = Parser_input(parser, data, count);
224 exit:
225 deallocate(data);
226 err = (err < 0 ? err : count);
227 return err;
228 }
230 static int proc_policy_release_fn(Inode *inode, File *file){
231 // User close.
232 // Cleanup file->private_data, return errcode.
233 int err = 0;
234 Parser *parser = NULL;
235 Sxpr obj, l;
237 dprintf(">\n");
238 err = proc_get_parser(file, &parser);
239 if(err) goto exit;
240 err = Parser_input(parser, NULL, 0);
241 if(err) goto exit;
242 obj = parser->val;
243 for(l = obj; CONSP(l); l = CDR(l)){
244 err = vnet_eval(CAR(l), iostdout, NULL);
245 if(err) break;
246 }
247 exit:
248 Parser_free(parser);
249 file->private_data = NULL;
250 dprintf("< err=%d\n", err);
251 return err;
252 }
254 static int proc_io_open(Inode *inode, File *file, IOStream **val){
255 int err = 0;
256 IOStream *io = mem_stream_new();
257 if(!io){
258 err = -ENOMEM;
259 goto exit;
260 }
261 file->private_data = io;
262 exit:
263 *val = (err ? NULL: io);
264 return err;
265 }
267 static ssize_t proc_io_read_fn(File *file, char *buffer,
268 size_t count, loff_t *offset){
269 // User read.
270 // Copy data to user buffer, increment offset by count, return count.
271 int err = 0;
272 char kbuf[1024] = {};
273 int kbuf_n = sizeof(kbuf);
274 int k, n = 0;
275 char *ubuf = buffer;
276 IOStream *io = file->private_data;
278 dprintf(">\n");
279 if(!io) goto exit;
280 while(n < count){
281 k = count - n;
282 if(k > kbuf_n){
283 k = kbuf_n;
284 }
285 k = IOStream_read(io, kbuf, k);
286 if(k <= 0) break;
287 if(copy_to_user(ubuf, kbuf, k)){
288 err = -EFAULT;
289 goto exit;
290 }
291 n += k;
292 ubuf += k;
293 }
294 *offset += n;
295 exit:
296 return (err ? err : n);
297 }
299 static int proc_io_release_fn(Inode *inode, File *file){
300 // User close.
301 int err = 0;
302 IOStream *io = file->private_data;
303 if(io) IOStream_close(io);
304 dprintf("< err=%d\n", err);
305 return err;
306 }
308 static int proc_vnets_open_fn(Inode *inode, File *file){
309 int err = 0;
310 IOStream *io;
311 if(proc_io_open(inode, file, &io)) goto exit;
312 vnet_print(io);
313 exit:
314 return err;
315 }
317 static int proc_vifs_open_fn(Inode *inode, File *file){
318 int err = 0;
319 IOStream *io;
320 if(proc_io_open(inode, file, &io)) goto exit;
321 vif_print(io);
322 exit:
323 return err;
324 }
326 static int proc_peers_open_fn(Inode *inode, File *file){
327 int err = 0;
328 IOStream *io;
329 if(proc_io_open(inode, file, &io)) goto exit;
330 vnet_peer_print(io);
331 exit:
332 return err;
333 }
335 static int proc_varp_open_fn(Inode *inode, File *file){
336 int err = 0;
337 IOStream *io;
338 if(proc_io_open(inode, file, &io)) goto exit;
339 varp_print(io);
340 exit:
341 return err;
342 }
344 static struct file_operations proc_policy_ops = {
345 open: proc_open_fn,
346 read: proc_read_fn,
347 write: proc_policy_write_fn,
348 //flush: proc_flush_fn,
349 llseek: proc_lseek_fn,
350 ioctl: proc_ioctl_fn,
351 release: proc_policy_release_fn,
352 };
354 static struct file_operations proc_vnets_ops = {
355 open: proc_vnets_open_fn,
356 read: proc_io_read_fn,
357 release: proc_io_release_fn,
358 };
360 static struct file_operations proc_vifs_ops = {
361 open: proc_vifs_open_fn,
362 read: proc_io_read_fn,
363 release: proc_io_release_fn,
364 };
366 static struct file_operations proc_peers_ops = {
367 open: proc_peers_open_fn,
368 read: proc_io_read_fn,
369 release: proc_io_release_fn,
370 };
372 static struct file_operations proc_varp_ops = {
373 open: proc_varp_open_fn,
374 read: proc_io_read_fn,
375 release: proc_io_release_fn,
376 };
378 static ProcEntry *proc_fs_root = &proc_root;
380 static int proc_path_init(const char *path, const char **rest){
381 int err = 0;
383 if(!path){
384 err = -EINVAL;
385 goto exit;
386 }
387 if(*path == '/'){
388 if(strncmp(PROC_ROOT, path, PROC_ROOT_LEN)){
389 err = -EINVAL;
390 } else {
391 path += PROC_ROOT_LEN;
392 }
393 }
394 exit:
395 *rest = path;
396 return err;
397 }
399 /** Parse a path relative to `dir'. If dir is null or the proc root
400 * the path is relative to "/proc/", and the leading "/proc/" may be
401 * supplied.
402 *
403 */
404 static ProcEntry * ProcFS_lookup(const char *path, ProcEntry *dir){
405 const char *pathptr = path, *next = NULL;
406 ProcEntry *entry, *result = NULL;
407 int pathlen;
409 if(dir && (dir != proc_fs_root)){
410 entry = dir;
411 } else {
412 if(proc_path_init(path, &pathptr)) goto exit;
413 entry = proc_fs_root;
414 }
415 if(!pathptr || !*pathptr) goto exit;
416 while(1){
417 next = strchr(pathptr, '/');
418 pathlen = (next ? next - pathptr : strlen(pathptr));
419 for(entry = entry->subdir; entry ; entry = entry->next) {
420 if(ProcEntry_has_name(entry, pathptr, pathlen)) break;
421 }
422 if (!entry) break;
423 if(!next){
424 result = entry;
425 break;
426 }
427 pathptr = next + 1;
428 }
429 exit:
430 return result;
431 }
433 static ProcEntry *ProcFS_register(const char *name, ProcEntry *dir,
434 int val, struct file_operations *ops){
435 mode_t mode = 0;
436 ProcEntry *entry;
438 entry = create_proc_entry(name, mode, dir);
439 if(entry){
440 entry->proc_fops = ops;
441 entry->data = (void*)val; // Whatever data we need.
442 }
443 return entry;
444 }
446 static ProcEntry *ProcFS_mkdir(const char *name, ProcEntry *parent){
447 ProcEntry *entry = NULL;
448 entry = ProcFS_lookup(name, parent);
449 if(!entry){
450 const char *path;
451 if(proc_path_init(name, &path)) goto exit;
452 entry = proc_mkdir(path, parent);
453 }
454 exit:
455 return entry;
456 }
458 static void ProcFS_remove(const char *name, ProcEntry *parent){
459 remove_proc_entry(name, parent);
460 }
462 static void ProcFS_rmrec_entry(ProcEntry *entry){
463 if(entry){
464 // Don't want to remove /proc itself!
465 if(entry->parent == entry) return;
466 while(entry->subdir){
467 ProcFS_rmrec_entry(entry->subdir);
468 }
469 dprintf("> remove %s\n", entry->name);
470 ProcFS_remove(entry->name, entry->parent);
471 }
472 }
474 static void ProcFS_rmrec(const char *name, ProcEntry *parent){
475 ProcEntry *entry;
477 dprintf("> name=%s\n", name);
478 entry = ProcFS_lookup(name, parent);
479 if(entry){
480 ProcFS_rmrec_entry(entry);
481 }
482 dprintf("<\n");
483 }
485 void __init ProcFS_init(void){
486 ProcEntry *root_entry;
487 ProcEntry *policy_entry;
488 ProcEntry *vnets_entry;
489 ProcEntry *vifs_entry;
490 ProcEntry *peers_entry;
491 ProcEntry *varp_entry;
493 dprintf(">\n");
494 root_entry = ProcFS_mkdir(MODULE_ROOT, NULL);
495 if(!root_entry) goto exit;
496 policy_entry = ProcFS_register("policy", root_entry, VNET_POLICY, &proc_policy_ops);
497 vnets_entry = ProcFS_register("vnets", root_entry, VNET_VNETS, &proc_vnets_ops);
498 vifs_entry = ProcFS_register("vifs", root_entry, VNET_VIFS, &proc_vifs_ops);
499 peers_entry = ProcFS_register("peers", root_entry, VNET_PEERS, &proc_peers_ops);
500 varp_entry = ProcFS_register("varp", root_entry, VNET_VARP, &proc_varp_ops);
501 exit:
502 dprintf("<\n");
503 }
505 void __exit ProcFS_exit(void){
506 dprintf(">\n");
507 ProcFS_rmrec(MODULE_ROOT, NULL);
508 dprintf("<\n");
509 }