Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
dgrp_specproc.c
Go to the documentation of this file.
1 /*
2  *
3  * Copyright 1999 Digi International (www.digi.com)
4  * James Puzzo <jamesp at digi dot com>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2, or (at your option)
9  * any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the
13  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14  * PURPOSE. See the GNU General Public License for more details.
15  *
16  */
17 
18 /*
19  *
20  * Filename:
21  *
22  * dgrp_specproc.c
23  *
24  * Description:
25  *
26  * Handle the "config" proc entry for the linux realport device driver
27  * and provide slots for the "net" and "mon" devices
28  *
29  * Author:
30  *
31  * James A. Puzzo
32  *
33  */
34 
35 #include <linux/module.h>
36 #include <linux/tty.h>
37 #include <linux/sched.h>
38 #include <linux/cred.h>
39 #include <linux/proc_fs.h>
40 #include <linux/ctype.h>
41 #include <linux/seq_file.h>
42 #include <linux/uaccess.h>
43 #include <linux/vmalloc.h>
44 
45 #include "dgrp_common.h"
46 
47 static struct dgrp_proc_entry dgrp_table[];
48 static struct proc_dir_entry *dgrp_proc_dir_entry;
49 
50 static int dgrp_add_id(long id);
51 static int dgrp_remove_nd(struct nd_struct *nd);
52 static void unregister_dgrp_device(struct proc_dir_entry *de);
53 static void register_dgrp_device(struct nd_struct *node,
54  struct proc_dir_entry *root,
55  void (*register_hook)(struct proc_dir_entry *de));
56 
57 /* File operation declarations */
58 static int dgrp_gen_proc_open(struct inode *, struct file *);
59 static int dgrp_gen_proc_close(struct inode *, struct file *);
60 static int parse_write_config(char *);
61 
62 
63 static const struct file_operations dgrp_proc_file_ops = {
64  .owner = THIS_MODULE,
65  .open = dgrp_gen_proc_open,
66  .release = dgrp_gen_proc_close,
67 };
68 
69 static struct inode_operations proc_inode_ops = {
70  .permission = dgrp_inode_permission
71 };
72 
73 
74 static void register_proc_table(struct dgrp_proc_entry *,
75  struct proc_dir_entry *);
76 static void unregister_proc_table(struct dgrp_proc_entry *,
77  struct proc_dir_entry *);
78 
79 static struct dgrp_proc_entry dgrp_net_table[];
80 static struct dgrp_proc_entry dgrp_mon_table[];
81 static struct dgrp_proc_entry dgrp_ports_table[];
82 static struct dgrp_proc_entry dgrp_dpa_table[];
83 
84 static ssize_t config_proc_write(struct file *file, const char __user *buffer,
85  size_t count, loff_t *pos);
86 
87 static int nodeinfo_proc_open(struct inode *inode, struct file *file);
88 static int info_proc_open(struct inode *inode, struct file *file);
89 static int config_proc_open(struct inode *inode, struct file *file);
90 
91 static struct file_operations config_proc_file_ops = {
92  .owner = THIS_MODULE,
93  .open = config_proc_open,
94  .read = seq_read,
95  .llseek = seq_lseek,
96  .release = seq_release,
97  .write = config_proc_write
98 };
99 
100 static struct file_operations info_proc_file_ops = {
101  .owner = THIS_MODULE,
102  .open = info_proc_open,
103  .read = seq_read,
104  .llseek = seq_lseek,
105  .release = seq_release,
106 };
107 
108 static struct file_operations nodeinfo_proc_file_ops = {
109  .owner = THIS_MODULE,
110  .open = nodeinfo_proc_open,
111  .read = seq_read,
112  .llseek = seq_lseek,
113  .release = seq_release,
114 };
115 
116 static struct dgrp_proc_entry dgrp_table[] = {
117  {
118  .id = DGRP_CONFIG,
119  .name = "config",
120  .mode = 0644,
121  .proc_file_ops = &config_proc_file_ops,
122  },
123  {
124  .id = DGRP_INFO,
125  .name = "info",
126  .mode = 0644,
127  .proc_file_ops = &info_proc_file_ops,
128  },
129  {
130  .id = DGRP_NODEINFO,
131  .name = "nodeinfo",
132  .mode = 0644,
133  .proc_file_ops = &nodeinfo_proc_file_ops,
134  },
135  {
136  .id = DGRP_NETDIR,
137  .name = "net",
138  .mode = 0500,
139  .child = dgrp_net_table
140  },
141  {
142  .id = DGRP_MONDIR,
143  .name = "mon",
144  .mode = 0500,
145  .child = dgrp_mon_table
146  },
147  {
148  .id = DGRP_PORTSDIR,
149  .name = "ports",
150  .mode = 0500,
151  .child = dgrp_ports_table
152  },
153  {
154  .id = DGRP_DPADIR,
155  .name = "dpa",
156  .mode = 0500,
157  .child = dgrp_dpa_table
158  }
159 };
160 
161 static struct proc_dir_entry *net_entry_pointer;
162 static struct proc_dir_entry *mon_entry_pointer;
163 static struct proc_dir_entry *dpa_entry_pointer;
164 static struct proc_dir_entry *ports_entry_pointer;
165 
166 static struct dgrp_proc_entry dgrp_net_table[] = {
167  {0}
168 };
169 
170 static struct dgrp_proc_entry dgrp_mon_table[] = {
171  {0}
172 };
173 
174 static struct dgrp_proc_entry dgrp_ports_table[] = {
175  {0}
176 };
177 
178 static struct dgrp_proc_entry dgrp_dpa_table[] = {
179  {0}
180 };
181 
183 {
184  unregister_proc_table(dgrp_table, dgrp_proc_dir_entry);
185  net_entry_pointer = NULL;
186  mon_entry_pointer = NULL;
187  dpa_entry_pointer = NULL;
188  ports_entry_pointer = NULL;
189 
190  if (dgrp_proc_dir_entry) {
191  remove_proc_entry(dgrp_proc_dir_entry->name,
192  dgrp_proc_dir_entry->parent);
193  dgrp_proc_dir_entry = NULL;
194  }
195 
196 }
197 
199 {
200  /*
201  * Register /proc/dgrp
202  */
203  dgrp_proc_dir_entry = proc_create("dgrp", S_IFDIR, NULL,
204  &dgrp_proc_file_ops);
205  register_proc_table(dgrp_table, dgrp_proc_dir_entry);
206 }
207 
208 /*
209  * /proc/sys support
210  */
211 static int dgrp_proc_match(int len, const char *name, struct proc_dir_entry *de)
212 {
213  if (!de || !de->low_ino)
214  return 0;
215  if (de->namelen != len)
216  return 0;
217  return !memcmp(name, de->name, len);
218 }
219 
220 
221 /*
222  * Scan the entries in table and add them all to /proc at the position
223  * referred to by "root"
224  */
225 static void register_proc_table(struct dgrp_proc_entry *table,
226  struct proc_dir_entry *root)
227 {
228  struct proc_dir_entry *de;
229  int len;
230  mode_t mode;
231 
232  if (table == NULL)
233  return;
234 
235  for (; table->id; table++) {
236  /* Can't do anything without a proc name. */
237  if (!table->name)
238  continue;
239 
240  /* Maybe we can't do anything with it... */
241  if (!table->proc_file_ops &&
242  !table->child) {
243  pr_warn("dgrp: Can't register %s\n",
244  table->name);
245  continue;
246  }
247 
248  len = strlen(table->name);
249  mode = table->mode;
250 
251  de = NULL;
252  if (!table->child)
253  mode |= S_IFREG;
254  else {
255  mode |= S_IFDIR;
256  for (de = root->subdir; de; de = de->next) {
257  if (dgrp_proc_match(len, table->name, de))
258  break;
259  }
260  /* If the subdir exists already, de is non-NULL */
261  }
262 
263  if (!de) {
264  de = create_proc_entry(table->name, mode, root);
265  if (!de)
266  continue;
267  de->data = (void *) table;
268  if (!table->child) {
269  de->proc_iops = &proc_inode_ops;
270  if (table->proc_file_ops)
271  de->proc_fops = table->proc_file_ops;
272  else
273  de->proc_fops = &dgrp_proc_file_ops;
274  }
275  }
276  table->de = de;
277  if (de->mode & S_IFDIR)
278  register_proc_table(table->child, de);
279 
280  if (table->id == DGRP_NETDIR)
281  net_entry_pointer = de;
282 
283  if (table->id == DGRP_MONDIR)
284  mon_entry_pointer = de;
285 
286  if (table->id == DGRP_DPADIR)
287  dpa_entry_pointer = de;
288 
289  if (table->id == DGRP_PORTSDIR)
290  ports_entry_pointer = de;
291  }
292 }
293 
294 /*
295  * Unregister a /proc sysctl table and any subdirectories.
296  */
297 static void unregister_proc_table(struct dgrp_proc_entry *table,
298  struct proc_dir_entry *root)
299 {
300  struct proc_dir_entry *de;
301  struct nd_struct *tmp;
302 
303  if (table == NULL)
304  return;
305 
307  if ((table == dgrp_net_table) && (tmp->nd_net_de)) {
308  unregister_dgrp_device(tmp->nd_net_de);
310  }
311 
312  if ((table == dgrp_mon_table) && (tmp->nd_mon_de))
313  unregister_dgrp_device(tmp->nd_mon_de);
314 
315  if ((table == dgrp_dpa_table) && (tmp->nd_dpa_de))
316  unregister_dgrp_device(tmp->nd_dpa_de);
317 
318  if ((table == dgrp_ports_table) && (tmp->nd_ports_de))
319  unregister_dgrp_device(tmp->nd_ports_de);
320  }
321 
322  for (; table->id; table++) {
323  de = table->de;
324 
325  if (!de)
326  continue;
327  if (de->mode & S_IFDIR) {
328  if (!table->child) {
329  pr_alert("dgrp: malformed sysctl tree on free\n");
330  continue;
331  }
332  unregister_proc_table(table->child, de);
333 
334  /* Don't unregister directories which still have entries */
335  if (de->subdir)
336  continue;
337  }
338 
339  /* Don't unregister proc entries that are still being used.. */
340  if ((atomic_read(&de->count)) != 1) {
341  pr_alert("proc entry %s in use, not removing\n",
342  de->name);
343  continue;
344  }
345 
346  remove_proc_entry(de->name, de->parent);
347  table->de = NULL;
348  }
349 }
350 
351 static int dgrp_gen_proc_open(struct inode *inode, struct file *file)
352 {
353  struct proc_dir_entry *de;
354  struct dgrp_proc_entry *entry;
355  int ret = 0;
356 
357  de = (struct proc_dir_entry *) PDE(file->f_dentry->d_inode);
358  if (!de || !de->data) {
359  ret = -ENXIO;
360  goto done;
361  }
362 
363  entry = (struct dgrp_proc_entry *) de->data;
364  if (!entry) {
365  ret = -ENXIO;
366  goto done;
367  }
368 
369  down(&entry->excl_sem);
370 
371  if (entry->excl_cnt)
372  ret = -EBUSY;
373  else
374  entry->excl_cnt++;
375 
376  up(&entry->excl_sem);
377 
378 done:
379  return ret;
380 }
381 
382 static int dgrp_gen_proc_close(struct inode *inode, struct file *file)
383 {
384  struct proc_dir_entry *de;
385  struct dgrp_proc_entry *entry;
386 
387  de = (struct proc_dir_entry *) PDE(file->f_dentry->d_inode);
388  if (!de || !de->data)
389  goto done;
390 
391  entry = (struct dgrp_proc_entry *) de->data;
392  if (!entry)
393  goto done;
394 
395  down(&entry->excl_sem);
396 
397  if (entry->excl_cnt)
398  entry->excl_cnt = 0;
399 
400  up(&entry->excl_sem);
401 
402 done:
403  return 0;
404 }
405 
406 static void *config_proc_start(struct seq_file *m, loff_t *pos)
407 {
408  return seq_list_start_head(&nd_struct_list, *pos);
409 }
410 
411 static void *config_proc_next(struct seq_file *p, void *v, loff_t *pos)
412 {
413  return seq_list_next(v, &nd_struct_list, pos);
414 }
415 
416 static void config_proc_stop(struct seq_file *m, void *v)
417 {
418 }
419 
420 static int config_proc_show(struct seq_file *m, void *v)
421 {
422  struct nd_struct *nd;
423  char tmp_id[4];
424 
425  if (v == &nd_struct_list) {
426  seq_puts(m, "#-----------------------------------------------------------------------------\n");
427  seq_puts(m, "# Avail\n");
428  seq_puts(m, "# ID Major State Ports\n");
429  return 0;
430  }
431 
432  nd = list_entry(v, struct nd_struct, list);
433 
434  ID_TO_CHAR(nd->nd_ID, tmp_id);
435 
436  seq_printf(m, " %-2.2s %-5ld %-10.10s %-5d\n",
437  tmp_id,
438  nd->nd_major,
439  ND_STATE_STR(nd->nd_state),
440  nd->nd_chan_count);
441 
442  return 0;
443 }
444 
445 static const struct seq_operations proc_config_ops = {
446  .start = config_proc_start,
447  .next = config_proc_next,
448  .stop = config_proc_stop,
449  .show = config_proc_show
450 };
451 
452 static int config_proc_open(struct inode *inode, struct file *file)
453 {
454  return seq_open(file, &proc_config_ops);
455 }
456 
457 
458 /*
459  * When writing configuration information, each "record" (i.e. each
460  * write) is treated as an independent request. See the "parse"
461  * description for more details.
462  */
463 static ssize_t config_proc_write(struct file *file, const char __user *buffer,
464  size_t count, loff_t *pos)
465 {
466  ssize_t retval;
467  char *inbuf, *sp;
468  char *line, *ldelim;
469 
470  if (count > 32768)
471  return -EINVAL;
472 
473  inbuf = sp = vzalloc(count + 1);
474  if (!inbuf)
475  return -ENOMEM;
476 
477  if (copy_from_user(inbuf, buffer, count)) {
478  retval = -EFAULT;
479  goto done;
480  }
481 
482  inbuf[count] = 0;
483 
484  ldelim = "\n";
485 
486  line = strpbrk(sp, ldelim);
487  while (line) {
488  *line = 0;
489  retval = parse_write_config(sp);
490  if (retval)
491  goto done;
492 
493  sp = line + 1;
494  line = strpbrk(sp, ldelim);
495  }
496 
497  retval = count;
498 done:
499  vfree(inbuf);
500  return retval;
501 }
502 
503 /*
504  * ------------------------------------------------------------------------
505  *
506  * The following are the functions to parse input
507  *
508  * ------------------------------------------------------------------------
509  */
510 static inline char *skip_past_ws(const char *str)
511 {
512  while ((*str) && !isspace(*str))
513  ++str;
514 
515  return skip_spaces(str);
516 }
517 
518 static int parse_id(char **c, char *cID)
519 {
520  int tmp = **c;
521 
522  if (isalnum(tmp) || (tmp == '_'))
523  cID[0] = tmp;
524  else
525  return -EINVAL;
526 
527  (*c)++; tmp = **c;
528 
529  if (isalnum(tmp) || (tmp == '_')) {
530  cID[1] = tmp;
531  (*c)++;
532  } else
533  cID[1] = 0;
534 
535  return 0;
536 }
537 
538 static int parse_add_config(char *buf)
539 {
540  char *c = buf;
541  int retval;
542  char cID[2];
543  long ID;
544 
545  c = skip_past_ws(c);
546 
547  retval = parse_id(&c, cID);
548  if (retval < 0)
549  return retval;
550 
551  ID = CHAR_TO_ID(cID);
552 
553  c = skip_past_ws(c);
554 
555  return dgrp_add_id(ID);
556 }
557 
558 static int parse_del_config(char *buf)
559 {
560  char *c = buf;
561  int retval;
562  struct nd_struct *nd;
563  char cID[2];
564  long ID;
565  long major;
566 
567  c = skip_past_ws(c);
568 
569  retval = parse_id(&c, cID);
570  if (retval < 0)
571  return retval;
572 
573  ID = CHAR_TO_ID(cID);
574 
575  c = skip_past_ws(c);
576 
577  retval = kstrtol(c, 10, &major);
578  if (retval)
579  return retval;
580 
581  nd = nd_struct_get(major);
582  if (!nd)
583  return -EINVAL;
584 
585  if ((nd->nd_major != major) || (nd->nd_ID != ID))
586  return -EINVAL;
587 
588  return dgrp_remove_nd(nd);
589 }
590 
591 static int parse_chg_config(char *buf)
592 {
593  return -EINVAL;
594 }
595 
596 /*
597  * The passed character buffer represents a single configuration request.
598  * If the first character is a "+", it is parsed as a request to add a
599  * PortServer
600  * If the first character is a "-", it is parsed as a request to delete a
601  * PortServer
602  * If the first character is a "*", it is parsed as a request to change a
603  * PortServer
604  * Any other character (including whitespace) causes the record to be
605  * ignored.
606  */
607 static int parse_write_config(char *buf)
608 {
609  int retval;
610 
611  switch (buf[0]) {
612  case '+':
613  retval = parse_add_config(buf);
614  break;
615  case '-':
616  retval = parse_del_config(buf);
617  break;
618  case '*':
619  retval = parse_chg_config(buf);
620  break;
621  default:
622  retval = -EINVAL;
623  }
624 
625  return retval;
626 }
627 
628 static int info_proc_show(struct seq_file *m, void *v)
629 {
630  seq_printf(m, "version: %s\n", DIGI_VERSION);
631  seq_puts(m, "register_with_sysfs: 1\n");
632  seq_printf(m, "rawreadok: 0x%08x\t(%d)\n",
634  seq_printf(m, "pollrate: 0x%08x\t(%d)\n",
636 
637  return 0;
638 }
639 
640 static int info_proc_open(struct inode *inode, struct file *file)
641 {
642  return single_open(file, info_proc_show, NULL);
643 }
644 
645 
646 static void *nodeinfo_start(struct seq_file *m, loff_t *pos)
647 {
648  return seq_list_start_head(&nd_struct_list, *pos);
649 }
650 
651 static void *nodeinfo_next(struct seq_file *p, void *v, loff_t *pos)
652 {
653  return seq_list_next(v, &nd_struct_list, pos);
654 }
655 
656 static void nodeinfo_stop(struct seq_file *m, void *v)
657 {
658 }
659 
660 static int nodeinfo_show(struct seq_file *m, void *v)
661 {
662  struct nd_struct *nd;
663  char hwver[8];
664  char swver[8];
665  char tmp_id[4];
666 
667  if (v == &nd_struct_list) {
668  seq_puts(m, "#-----------------------------------------------------------------------------\n");
669  seq_puts(m, "# HW HW SW\n");
670  seq_puts(m, "# ID State Version ID Version Description\n");
671  return 0;
672  }
673 
674  nd = list_entry(v, struct nd_struct, list);
675 
676  ID_TO_CHAR(nd->nd_ID, tmp_id);
677 
678  if (nd->nd_state == NS_READY) {
679  sprintf(hwver, "%d.%d", (nd->nd_hw_ver >> 8) & 0xff,
680  nd->nd_hw_ver & 0xff);
681  sprintf(swver, "%d.%d", (nd->nd_sw_ver >> 8) & 0xff,
682  nd->nd_sw_ver & 0xff);
683  seq_printf(m, " %-2.2s %-10.10s %-7.7s %-3d %-7.7s %-35.35s\n",
684  tmp_id,
685  ND_STATE_STR(nd->nd_state),
686  hwver,
687  nd->nd_hw_id,
688  swver,
689  nd->nd_ps_desc);
690 
691  } else {
692  seq_printf(m, " %-2.2s %-10.10s\n",
693  tmp_id,
694  ND_STATE_STR(nd->nd_state));
695  }
696 
697  return 0;
698 }
699 
700 
701 static const struct seq_operations nodeinfo_ops = {
702  .start = nodeinfo_start,
703  .next = nodeinfo_next,
704  .stop = nodeinfo_stop,
705  .show = nodeinfo_show
706 };
707 
708 static int nodeinfo_proc_open(struct inode *inode, struct file *file)
709 {
710  return seq_open(file, &nodeinfo_ops);
711 }
712 
717 static int dgrp_add_id(long id)
718 {
719  struct nd_struct *nd;
720  int ret;
721  int i;
722 
723  nd = kzalloc(sizeof(struct nd_struct), GFP_KERNEL);
724  if (!nd)
725  return -ENOMEM;
726 
727  nd->nd_major = 0;
728  nd->nd_ID = id;
729 
730  spin_lock_init(&nd->nd_lock);
731 
735  for (i = 0; i < SEQ_MAX; i++)
737 
738  /* setup the structures to get the major number */
739  ret = dgrp_tty_init(nd);
740  if (ret)
741  goto error_out;
742 
743  nd->nd_major = nd->nd_serial_ttdriver->major;
744 
745  ret = nd_struct_add(nd);
746  if (ret)
747  goto error_out;
748 
749  register_dgrp_device(nd, net_entry_pointer, dgrp_register_net_hook);
750  register_dgrp_device(nd, mon_entry_pointer, dgrp_register_mon_hook);
751  register_dgrp_device(nd, dpa_entry_pointer, dgrp_register_dpa_hook);
752  register_dgrp_device(nd, ports_entry_pointer,
754 
755  return 0;
756 
757 error_out:
758  kfree(nd);
759  return ret;
760 
761 }
762 
763 static int dgrp_remove_nd(struct nd_struct *nd)
764 {
765  int ret;
766 
767  /* Check to see if the selected structure is in use */
768  if (nd->nd_tty_ref_cnt)
769  return -EBUSY;
770 
771  if (nd->nd_net_de) {
772  unregister_dgrp_device(nd->nd_net_de);
774  }
775 
776  if (nd->nd_mon_de)
777  unregister_dgrp_device(nd->nd_mon_de);
778 
779  if (nd->nd_ports_de)
780  unregister_dgrp_device(nd->nd_ports_de);
781 
782  if (nd->nd_dpa_de)
783  unregister_dgrp_device(nd->nd_dpa_de);
784 
785  dgrp_tty_uninit(nd);
786 
787  ret = nd_struct_del(nd);
788  if (ret)
789  return ret;
790 
791  kfree(nd);
792  return 0;
793 }
794 
795 static void register_dgrp_device(struct nd_struct *node,
796  struct proc_dir_entry *root,
797  void (*register_hook)(struct proc_dir_entry *de))
798 {
799  char buf[3];
800  struct proc_dir_entry *de;
801 
802  ID_TO_CHAR(node->nd_ID, buf);
803 
804  de = create_proc_entry(buf, 0600 | S_IFREG, root);
805  if (!de)
806  return;
807 
808  de->data = (void *) node;
809 
810  if (register_hook)
811  register_hook(de);
812 
813 }
814 
815 static void unregister_dgrp_device(struct proc_dir_entry *de)
816 {
817  if (!de)
818  return;
819 
820  /* Don't unregister proc entries that are still being used.. */
821  if ((atomic_read(&de->count)) != 1) {
822  pr_alert("%s - proc entry %s in use. Not removing.\n",
823  __func__, de->name);
824  return;
825  }
826 
827  remove_proc_entry(de->name, de->parent);
828  de = NULL;
829 }