proc.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:16k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /* net/atm/proc.c - ATM /proc interface */
  2. /* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */
  3. /*
  4.  * The mechanism used here isn't designed for speed but rather for convenience
  5.  * of implementation. We only return one entry per read system call, so we can
  6.  * be reasonably sure not to overrun the page and race conditions may lead to
  7.  * the addition or omission of some lines but never to any corruption of a
  8.  * line's internal structure.
  9.  *
  10.  * Making the whole thing slightly more efficient is left as an exercise to the
  11.  * reader. (Suggestions: wrapper which loops to get several entries per system
  12.  * call; or make --left slightly more clever to avoid O(n^2) characteristics.)
  13.  * I find it fast enough on my unloaded 266 MHz Pentium 2 :-)
  14.  */
  15. #include <linux/config.h>
  16. #include <linux/module.h> /* for EXPORT_SYMBOL */
  17. #include <linux/string.h>
  18. #include <linux/types.h>
  19. #include <linux/mm.h>
  20. #include <linux/fs.h>
  21. #include <linux/stat.h>
  22. #include <linux/proc_fs.h>
  23. #include <linux/errno.h>
  24. #include <linux/atm.h>
  25. #include <linux/atmdev.h>
  26. #include <linux/netdevice.h>
  27. #include <linux/atmclip.h>
  28. #include <linux/atmarp.h>
  29. #include <linux/if_arp.h>
  30. #include <linux/init.h> /* for __init */
  31. #include <asm/uaccess.h>
  32. #include <asm/atomic.h>
  33. #include <asm/param.h> /* for HZ */
  34. #include "resources.h"
  35. #include "common.h" /* atm_proc_init prototype */
  36. #include "signaling.h" /* to get sigd - ugly too */
  37. #ifdef CONFIG_ATM_CLIP
  38. #include <net/atmclip.h>
  39. #include "ipcommon.h"
  40. extern void clip_push(struct atm_vcc *vcc,struct sk_buff *skb);
  41. #endif
  42. #if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE)
  43. #include "lec.h"
  44. #include "lec_arpc.h"
  45. extern struct atm_lane_ops atm_lane_ops; /* in common.c */
  46. #endif
  47. static ssize_t proc_dev_atm_read(struct file *file,char *buf,size_t count,
  48.     loff_t *pos);
  49. static ssize_t proc_spec_atm_read(struct file *file,char *buf,size_t count,
  50.     loff_t *pos);
  51. static struct file_operations proc_dev_atm_operations = {
  52. read: proc_dev_atm_read,
  53. };
  54. static struct file_operations proc_spec_atm_operations = {
  55. read: proc_spec_atm_read,
  56. };
  57. static void add_stats(char *buf,const char *aal,
  58.   const struct k_atm_aal_stats *stats)
  59. {
  60. sprintf(strchr(buf,0),"%s ( %d %d %d %d %d )",aal,
  61.     atomic_read(&stats->tx),atomic_read(&stats->tx_err),
  62.     atomic_read(&stats->rx),atomic_read(&stats->rx_err),
  63.     atomic_read(&stats->rx_drop));
  64. }
  65. static void dev_info(const struct atm_dev *dev,char *buf)
  66. {
  67. int off,i;
  68. off = sprintf(buf,"%3d %-8s",dev->number,dev->type);
  69. for (i = 0; i < ESI_LEN; i++)
  70. off += sprintf(buf+off,"%02x",dev->esi[i]);
  71. strcat(buf,"  ");
  72. add_stats(buf,"0",&dev->stats.aal0);
  73. strcat(buf,"  ");
  74. add_stats(buf,"5",&dev->stats.aal5);
  75. strcat(buf,"n");
  76. }
  77. #ifdef CONFIG_ATM_CLIP
  78. static int svc_addr(char *buf,struct sockaddr_atmsvc *addr)
  79. {
  80. static int code[] = { 1,2,10,6,1,0 };
  81. static int e164[] = { 1,8,4,6,1,0 };
  82. int *fields;
  83. int len,i,j,pos;
  84. len = 0;
  85. if (*addr->sas_addr.pub) {
  86. strcpy(buf,addr->sas_addr.pub);
  87. len = strlen(addr->sas_addr.pub);
  88. buf += len;
  89. if (*addr->sas_addr.prv) {
  90. *buf++ = '+';
  91. len++;
  92. }
  93. }
  94. else if (!*addr->sas_addr.prv) {
  95. strcpy(buf,"(none)");
  96. return strlen(buf);
  97. }
  98. if (*addr->sas_addr.prv) {
  99. len += 44;
  100. pos = 0;
  101. fields = *addr->sas_addr.prv == ATM_AFI_E164 ? e164 : code;
  102. for (i = 0; fields[i]; i++) {
  103. for (j = fields[i]; j; j--) {
  104. sprintf(buf,"%02X",addr->sas_addr.prv[pos++]);
  105. buf += 2;
  106. }
  107. if (fields[i+1]) *buf++ = '.';
  108. }
  109. }
  110. return len;
  111. }
  112. static void atmarp_info(struct net_device *dev,struct atmarp_entry *entry,
  113.     struct clip_vcc *clip_vcc,char *buf)
  114. {
  115. unsigned char *ip;
  116. int svc,off,ip_len;
  117. svc = !clip_vcc || clip_vcc->vcc->family == AF_ATMSVC;
  118. off = sprintf(buf,"%-6s%-4s%-4s%5ld ",dev->name,svc ? "SVC" : "PVC",
  119.     !clip_vcc || clip_vcc->encap ? "LLC" : "NULL",
  120.     (jiffies-(clip_vcc ? clip_vcc->last_use : entry->neigh->used))/
  121.     HZ);
  122. ip = (unsigned char *) &entry->ip;
  123. ip_len = sprintf(buf+off,"%d.%d.%d.%d",ip[0],ip[1],ip[2],ip[3]);
  124. off += ip_len;
  125. while (ip_len++ < 16) buf[off++] = ' ';
  126. if (!clip_vcc)
  127. if (time_before(jiffies, entry->expires))
  128. strcpy(buf+off,"(resolving)n");
  129. else sprintf(buf+off,"(expired, ref %d)n",
  130.     atomic_read(&entry->neigh->refcnt));
  131. else if (!svc)
  132. sprintf(buf+off,"%d.%d.%dn",clip_vcc->vcc->dev->number,
  133.     clip_vcc->vcc->vpi,clip_vcc->vcc->vci);
  134. else {
  135. off += svc_addr(buf+off,&clip_vcc->vcc->remote);
  136. strcpy(buf+off,"n");
  137. }
  138. }
  139. #endif
  140. static void pvc_info(struct atm_vcc *vcc,char *buf)
  141. {
  142. static const char *class_name[] = { "off","UBR","CBR","VBR","ABR" };
  143. static const char *aal_name[] = {
  144. "---", "1", "2", "3/4", /*  0- 3 */
  145. "???", "5", "???", "???", /*  4- 7 */
  146. "???", "???", "???", "???", /*  8-11 */
  147. "???", "0", "???", "???"}; /* 12-15 */
  148. int off;
  149. off = sprintf(buf,"%3d %3d %5d %-3s %7d %-5s %7d %-6s",
  150.     vcc->dev->number,vcc->vpi,vcc->vci,
  151.     vcc->qos.aal >= sizeof(aal_name)/sizeof(aal_name[0]) ? "err" :
  152.     aal_name[vcc->qos.aal],vcc->qos.rxtp.min_pcr,
  153.     class_name[vcc->qos.rxtp.traffic_class],vcc->qos.txtp.min_pcr,
  154.     class_name[vcc->qos.txtp.traffic_class]);
  155. #ifdef CONFIG_ATM_CLIP
  156. if (vcc->push == clip_push) {
  157. struct clip_vcc *clip_vcc = CLIP_VCC(vcc);
  158. struct net_device *dev;
  159. dev = clip_vcc->entry ? clip_vcc->entry->neigh->dev : NULL;
  160. off += sprintf(buf+off,"CLIP, Itf:%s, Encap:",
  161.     dev ? dev->name : "none?");
  162. if (clip_vcc->encap) off += sprintf(buf+off,"LLC/SNAP");
  163. else off += sprintf(buf+off,"None");
  164. }
  165. #endif
  166. strcpy(buf+off,"n");
  167. }
  168. static const char *vcc_state(struct atm_vcc *vcc)
  169. {
  170. static const char *map[] = { ATM_VS2TXT_MAP };
  171. return map[ATM_VF2VS(vcc->flags)];
  172. }
  173. static void vc_info(struct atm_vcc *vcc,char *buf)
  174. {
  175. char *here;
  176. here = buf+sprintf(buf,"%p ",vcc);
  177. if (!vcc->dev) here += sprintf(here,"Unassigned    ");
  178. else here += sprintf(here,"%3d %3d %5d ",vcc->dev->number,vcc->vpi,
  179.     vcc->vci);
  180. switch (vcc->family) {
  181. case AF_ATMPVC:
  182. here += sprintf(here,"PVC");
  183. break;
  184. case AF_ATMSVC:
  185. here += sprintf(here,"SVC");
  186. break;
  187. default:
  188. here += sprintf(here,"%3d",vcc->family);
  189. }
  190. here += sprintf(here," %04lx  %5d %7d/%7d %7d/%7dn",vcc->flags.bits,
  191.     vcc->reply,
  192.     atomic_read(&vcc->tx_inuse),vcc->sk->sndbuf,
  193.     atomic_read(&vcc->rx_inuse),vcc->sk->rcvbuf);
  194. }
  195. static void svc_info(struct atm_vcc *vcc,char *buf)
  196. {
  197. char *here;
  198. int i;
  199. if (!vcc->dev)
  200. sprintf(buf,sizeof(void *) == 4 ? "N/A@%p%10s" : "N/A@%p%2s",
  201.     vcc,"");
  202. else sprintf(buf,"%3d %3d %5d         ",vcc->dev->number,vcc->vpi,
  203.     vcc->vci);
  204. here = strchr(buf,0);
  205. here += sprintf(here,"%-10s ",vcc_state(vcc));
  206. here += sprintf(here,"%s%s",vcc->remote.sas_addr.pub,
  207.     *vcc->remote.sas_addr.pub && *vcc->remote.sas_addr.prv ? "+" : "");
  208. if (*vcc->remote.sas_addr.prv)
  209. for (i = 0; i < ATM_ESA_LEN; i++)
  210. here += sprintf(here,"%02x",
  211.     vcc->remote.sas_addr.prv[i]);
  212. strcat(here,"n");
  213. }
  214. #if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE)
  215. static char*
  216. lec_arp_get_status_string(unsigned char status)
  217. {
  218.   switch(status) {
  219.   case ESI_UNKNOWN:
  220.     return "ESI_UNKNOWN       ";
  221.   case ESI_ARP_PENDING:
  222.     return "ESI_ARP_PENDING   ";
  223.   case ESI_VC_PENDING:
  224.     return "ESI_VC_PENDING    ";
  225.   case ESI_FLUSH_PENDING:
  226.     return "ESI_FLUSH_PENDING ";
  227.   case ESI_FORWARD_DIRECT:
  228.     return "ESI_FORWARD_DIRECT";
  229.   default:
  230.     return "<Unknown>         ";
  231.   }
  232. }
  233. static void 
  234. lec_info(struct lec_arp_table *entry, char *buf)
  235. {
  236.         int j, offset=0;
  237.         for(j=0;j<ETH_ALEN;j++) {
  238.                 offset+=sprintf(buf+offset,"%2.2x",0xff&entry->mac_addr[j]);
  239.         }
  240.         offset+=sprintf(buf+offset, " ");
  241.         for(j=0;j<ATM_ESA_LEN;j++) {
  242.                 offset+=sprintf(buf+offset,"%2.2x",0xff&entry->atm_addr[j]);
  243.         }
  244.         offset+=sprintf(buf+offset, " %s %4.4x",
  245.                         lec_arp_get_status_string(entry->status),
  246.                         entry->flags&0xffff);
  247.         if (entry->vcc) {
  248.                 offset+=sprintf(buf+offset, "%3d %3d ", entry->vcc->vpi, 
  249.                                 entry->vcc->vci);                
  250.         } else
  251.                 offset+=sprintf(buf+offset, "        ");
  252.         if (entry->recv_vcc) {
  253.                 offset+=sprintf(buf+offset, "     %3d %3d", 
  254.                                 entry->recv_vcc->vpi, entry->recv_vcc->vci);
  255.         }
  256.         sprintf(buf+offset,"n");
  257. }
  258. #endif
  259. static int atm_devices_info(loff_t pos,char *buf)
  260. {
  261. struct atm_dev *dev;
  262. int left;
  263. if (!pos) {
  264. return sprintf(buf,"Itf Type    ESI/"MAC"addr "
  265.     "AAL(TX,err,RX,err,drop) ...n");
  266. }
  267. left = pos-1;
  268. for (dev = atm_devs; dev && left; dev = dev->next) left--;
  269. if (!dev) return 0;
  270. dev_info(dev,buf);
  271. return strlen(buf);
  272. }
  273. /*
  274.  * FIXME: it isn't safe to walk the VCC list without turning off interrupts.
  275.  * What is really needed is some lock on the devices. Ditto for ATMARP.
  276.  */
  277. static int atm_pvc_info(loff_t pos,char *buf)
  278. {
  279. struct atm_dev *dev;
  280. struct atm_vcc *vcc;
  281. int left;
  282. if (!pos) {
  283. return sprintf(buf,"Itf VPI VCI   AAL RX(PCR,Class) "
  284.     "TX(PCR,Class)n");
  285. }
  286. left = pos-1;
  287. for (dev = atm_devs; dev; dev = dev->next)
  288. for (vcc = dev->vccs; vcc; vcc = vcc->next)
  289. if (vcc->family == PF_ATMPVC &&
  290.     vcc->dev && !left--) {
  291. pvc_info(vcc,buf);
  292. return strlen(buf);
  293. }
  294. return 0;
  295. }
  296. static int atm_vc_info(loff_t pos,char *buf)
  297. {
  298. struct atm_dev *dev;
  299. struct atm_vcc *vcc;
  300. int left;
  301. if (!pos)
  302. return sprintf(buf,sizeof(void *) == 4 ? "%-8s%s" : "%-16s%s",
  303.     "Address"," Itf VPI VCI   Fam Flags Reply Send buffer"
  304.     "     Recv buffern");
  305. left = pos-1;
  306. for (dev = atm_devs; dev; dev = dev->next)
  307. for (vcc = dev->vccs; vcc; vcc = vcc->next)
  308. if (!left--) {
  309. vc_info(vcc,buf);
  310. return strlen(buf);
  311. }
  312. for (vcc = nodev_vccs; vcc; vcc = vcc->next)
  313. if (!left--) {
  314. vc_info(vcc,buf);
  315. return strlen(buf);
  316. }
  317. return 0;
  318. }
  319. static int atm_svc_info(loff_t pos,char *buf)
  320. {
  321. struct atm_dev *dev;
  322. struct atm_vcc *vcc;
  323. int left;
  324. if (!pos)
  325. return sprintf(buf,"Itf VPI VCI           State      Remoten");
  326. left = pos-1;
  327. for (dev = atm_devs; dev; dev = dev->next)
  328. for (vcc = dev->vccs; vcc; vcc = vcc->next)
  329. if (vcc->family == PF_ATMSVC && !left--) {
  330. svc_info(vcc,buf);
  331. return strlen(buf);
  332. }
  333. for (vcc = nodev_vccs; vcc; vcc = vcc->next)
  334. if (vcc->family == PF_ATMSVC && !left--) {
  335. svc_info(vcc,buf);
  336. return strlen(buf);
  337. }
  338. return 0;
  339. }
  340. #ifdef CONFIG_ATM_CLIP
  341. static int atm_arp_info(loff_t pos,char *buf)
  342. {
  343. struct neighbour *n;
  344. int i,count;
  345. if (!pos) {
  346. return sprintf(buf,"IPitf TypeEncp Idle IP address      "
  347.     "ATM addressn");
  348. }
  349. count = pos;
  350. read_lock_bh(&clip_tbl.lock);
  351. for (i = 0; i <= NEIGH_HASHMASK; i++)
  352. for (n = clip_tbl.hash_buckets[i]; n; n = n->next) {
  353. struct atmarp_entry *entry = NEIGH2ENTRY(n);
  354. struct clip_vcc *vcc;
  355. if (!entry->vccs) {
  356. if (--count) continue;
  357. atmarp_info(n->dev,entry,NULL,buf);
  358. read_unlock_bh(&clip_tbl.lock);
  359. return strlen(buf);
  360. }
  361. for (vcc = entry->vccs; vcc;
  362.     vcc = vcc->next) {
  363. if (--count) continue;
  364. atmarp_info(n->dev,entry,vcc,buf);
  365. read_unlock_bh(&clip_tbl.lock);
  366. return strlen(buf);
  367. }
  368. }
  369. read_unlock_bh(&clip_tbl.lock);
  370. return 0;
  371. }
  372. #endif
  373. #if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE)
  374. static int atm_lec_info(loff_t pos,char *buf)
  375. {
  376. struct lec_priv *priv;
  377. struct lec_arp_table *entry;
  378. int i, count, d, e;
  379. struct net_device **dev_lec;
  380. if (!pos) {
  381. return sprintf(buf,"Itf  MAC          ATM destination"
  382.     "                          Status            Flags "
  383.     "VPI/VCI Recv VPI/VCIn");
  384. }
  385. if (atm_lane_ops.get_lecs == NULL)
  386. return 0; /* the lane module is not there yet */
  387. else
  388. dev_lec = atm_lane_ops.get_lecs();
  389. count = pos;
  390. for(d=0;d<MAX_LEC_ITF;d++) {
  391. if (!dev_lec[d] || !(priv =
  392.     (struct lec_priv *) dev_lec[d]->priv)) continue;
  393. for(i=0;i<LEC_ARP_TABLE_SIZE;i++) {
  394. entry = priv->lec_arp_tables[i];
  395. for(;entry;entry=entry->next) {
  396. if (--count) continue;
  397. e=sprintf(buf,"%s ",
  398.     dev_lec[d]->name);
  399. lec_info(entry,buf+e);
  400. return strlen(buf);
  401. }
  402. }
  403. for(entry=priv->lec_arp_empty_ones; entry;
  404.     entry=entry->next) {
  405. if (--count) continue;
  406. e=sprintf(buf,"%s ",dev_lec[d]->name);
  407. lec_info(entry, buf+e);
  408. return strlen(buf);
  409. }
  410. for(entry=priv->lec_no_forward; entry;
  411.     entry=entry->next) {
  412. if (--count) continue;
  413. e=sprintf(buf,"%s ",dev_lec[d]->name);
  414. lec_info(entry, buf+e);
  415. return strlen(buf);
  416. }
  417. for(entry=priv->mcast_fwds; entry;
  418.     entry=entry->next) {
  419. if (--count) continue;
  420. e=sprintf(buf,"%s ",dev_lec[d]->name);
  421. lec_info(entry, buf+e);
  422. return strlen(buf);
  423. }
  424. }
  425. return 0;
  426. }
  427. #endif
  428. static ssize_t proc_dev_atm_read(struct file *file,char *buf,size_t count,
  429.     loff_t *pos)
  430. {
  431. struct atm_dev *dev;
  432. unsigned long page;
  433. int length;
  434. if (count == 0) return 0;
  435. page = get_free_page(GFP_KERNEL);
  436. if (!page) return -ENOMEM;
  437. dev = ((struct proc_dir_entry *) file->f_dentry->d_inode->u.generic_ip)
  438.     ->data;
  439. if (!dev->ops->proc_read)
  440. length = -EINVAL;
  441. else {
  442. length = dev->ops->proc_read(dev,pos,(char *) page);
  443. if (length > count) length = -EINVAL;
  444. }
  445. if (length >= 0) {
  446. if (copy_to_user(buf,(char *) page,length)) length = -EFAULT;
  447. (*pos)++;
  448. }
  449. free_page(page);
  450. return length;
  451. }
  452. static ssize_t proc_spec_atm_read(struct file *file,char *buf,size_t count,
  453.     loff_t *pos)
  454. {
  455. unsigned long page;
  456. int length;
  457. int (*info)(loff_t,char *);
  458. info = ((struct proc_dir_entry *) file->f_dentry->d_inode->u.generic_ip)
  459.     ->data;
  460. if (count == 0) return 0;
  461. page = get_free_page(GFP_KERNEL);
  462. if (!page) return -ENOMEM;
  463. length = (*info)(*pos,(char *) page);
  464. if (length > count) length = -EINVAL;
  465. if (length >= 0) {
  466. if (copy_to_user(buf,(char *) page,length)) length = -EFAULT;
  467. (*pos)++;
  468. }
  469. free_page(page);
  470. return length;
  471. }
  472. struct proc_dir_entry *atm_proc_root;
  473. EXPORT_SYMBOL(atm_proc_root);
  474. int atm_proc_dev_register(struct atm_dev *dev)
  475. {
  476. int digits,num;
  477. int error;
  478. error = -ENOMEM;
  479. digits = 0;
  480. for (num = dev->number; num; num /= 10) digits++;
  481. if (!digits) digits++;
  482. dev->proc_name = kmalloc(strlen(dev->type)+digits+2,GFP_KERNEL);
  483. if (!dev->proc_name) goto fail1;
  484. sprintf(dev->proc_name,"%s:%d",dev->type, dev->number);
  485. dev->proc_entry = create_proc_entry(dev->proc_name, 0, atm_proc_root);
  486. if (!dev->proc_entry)
  487. goto fail0;
  488. dev->proc_entry->data = dev;
  489. dev->proc_entry->proc_fops = &proc_dev_atm_operations;
  490. dev->proc_entry->owner = THIS_MODULE;
  491. return 0;
  492. fail0:
  493. kfree(dev->proc_name);
  494. fail1:
  495. return error;
  496. }
  497. void atm_proc_dev_deregister(struct atm_dev *dev)
  498. {
  499. remove_proc_entry(dev->proc_name, atm_proc_root);
  500. kfree(dev->proc_name);
  501. }
  502. #define CREATE_ENTRY(name) 
  503.     name = create_proc_entry(#name,0,atm_proc_root); 
  504.     if (!name) goto cleanup; 
  505.     name->data = atm_##name##_info; 
  506.     name->proc_fops = &proc_spec_atm_operations; 
  507.     name->owner = THIS_MODULE
  508. int __init atm_proc_init(void)
  509. {
  510. struct proc_dir_entry *devices = NULL,*pvc = NULL,*svc = NULL;
  511. struct proc_dir_entry *arp = NULL,*lec = NULL,*vc = NULL;
  512. atm_proc_root = proc_mkdir("net/atm",NULL);
  513. if (!atm_proc_root)
  514. return -ENOMEM;
  515. CREATE_ENTRY(devices);
  516. CREATE_ENTRY(pvc);
  517. CREATE_ENTRY(svc);
  518. CREATE_ENTRY(vc);
  519. #ifdef CONFIG_ATM_CLIP
  520. CREATE_ENTRY(arp);
  521. #endif
  522. #if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE)
  523. CREATE_ENTRY(lec);
  524. #endif
  525. return 0;
  526. cleanup:
  527. if (devices) remove_proc_entry("devices",atm_proc_root);
  528. if (pvc) remove_proc_entry("pvc",atm_proc_root);
  529. if (svc) remove_proc_entry("svc",atm_proc_root);
  530. if (arp) remove_proc_entry("arp",atm_proc_root);
  531. if (lec) remove_proc_entry("lec",atm_proc_root);
  532. if (vc) remove_proc_entry("vc",atm_proc_root);
  533. remove_proc_entry("net/atm",NULL);
  534. return -ENOMEM;
  535. }