~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/net/atm/proc.c

Version: ~ [ linux-6.4-rc3 ] ~ [ linux-6.3.4 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.30 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.113 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.180 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.243 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.283 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.315 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /* net/atm/proc.c - ATM /proc interface */
  2 
  3 /* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */
  4 
  5 /*
  6  * The mechanism used here isn't designed for speed but rather for convenience
  7  * of implementation. We only return one entry per read system call, so we can
  8  * be reasonably sure not to overrun the page and race conditions may lead to
  9  * the addition or omission of some lines but never to any corruption of a
 10  * line's internal structure.
 11  *
 12  * Making the whole thing slightly more efficient is left as an exercise to the
 13  * reader. (Suggestions: wrapper which loops to get several entries per system
 14  * call; or make --left slightly more clever to avoid O(n^2) characteristics.)
 15  * I find it fast enough on my unloaded 266 MHz Pentium 2 :-)
 16  */
 17 
 18 
 19 #include <linux/config.h>
 20 #include <linux/module.h> /* for EXPORT_SYMBOL */
 21 #include <linux/string.h>
 22 #include <linux/types.h>
 23 #include <linux/mm.h>
 24 #include <linux/fs.h>
 25 #include <linux/stat.h>
 26 #include <linux/proc_fs.h>
 27 #include <linux/errno.h>
 28 #include <linux/atm.h>
 29 #include <linux/atmdev.h>
 30 #include <linux/netdevice.h>
 31 #include <linux/atmclip.h>
 32 #include <linux/atmarp.h>
 33 #include <linux/if_arp.h>
 34 #include <linux/init.h> /* for __init */
 35 #include <asm/uaccess.h>
 36 #include <asm/atomic.h>
 37 #include <asm/param.h> /* for HZ */
 38 #include "resources.h"
 39 #include "common.h" /* atm_proc_init prototype */
 40 #include "signaling.h" /* to get sigd - ugly too */
 41 
 42 #if defined(CONFIG_ATM_CLIP) || defined(CONFIG_ATM_CLIP_MODULE)
 43 #include <net/atmclip.h>
 44 #include "ipcommon.h"
 45 #endif
 46 
 47 #if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE)
 48 #include "lec.h"
 49 #include "lec_arpc.h"
 50 #endif
 51 
 52 static ssize_t proc_dev_atm_read(struct file *file,char *buf,size_t count,
 53     loff_t *pos);
 54 static ssize_t proc_spec_atm_read(struct file *file,char *buf,size_t count,
 55     loff_t *pos);
 56 
 57 static struct file_operations proc_dev_atm_operations = {
 58         read:           proc_dev_atm_read,
 59 };
 60 
 61 static struct file_operations proc_spec_atm_operations = {
 62         read:           proc_spec_atm_read,
 63 };
 64 
 65 static void add_stats(char *buf,const char *aal,
 66   const struct k_atm_aal_stats *stats)
 67 {
 68         sprintf(strchr(buf,0),"%s ( %d %d %d %d %d )",aal,
 69             atomic_read(&stats->tx),atomic_read(&stats->tx_err),
 70             atomic_read(&stats->rx),atomic_read(&stats->rx_err),
 71             atomic_read(&stats->rx_drop));
 72 }
 73 
 74 
 75 static void dev_info(const struct atm_dev *dev,char *buf)
 76 {
 77         int off,i;
 78 
 79         off = sprintf(buf,"%3d %-8s",dev->number,dev->type);
 80         for (i = 0; i < ESI_LEN; i++)
 81                 off += sprintf(buf+off,"%02x",dev->esi[i]);
 82         strcat(buf,"  ");
 83         add_stats(buf,"",&dev->stats.aal0);
 84         strcat(buf,"  ");
 85         add_stats(buf,"5",&dev->stats.aal5);
 86         sprintf(strchr(buf,0), "\t[%d]", atomic_read(&dev->refcnt));
 87         strcat(buf,"\n");
 88 }
 89 
 90 
 91 #if defined(CONFIG_ATM_CLIP) || defined(CONFIG_ATM_CLIP_MODULE)
 92 
 93 #define SEQ_NO_VCC_TOKEN   ((void *) 2)
 94 
 95 static void svc_addr(struct seq_file *seq, struct sockaddr_atmsvc *addr)
 96 {
 97         static int code[] = { 1,2,10,6,1,0 };
 98         static int e164[] = { 1,8,4,6,1,0 };
 99 
100         if (*addr->sas_addr.pub) {
101                 seq_printf(seq, "%s", addr->sas_addr.pub);
102                 if (*addr->sas_addr.prv)
103                         seq_putc(seq, '+');
104         } else if (!*addr->sas_addr.prv) {
105                 seq_printf(seq, "%s", "(none)");
106                 return;
107         }
108         if (*addr->sas_addr.prv) {
109                 unsigned char *prv = addr->sas_addr.prv;
110                 int *fields;
111                 int i, j;
112 
113                 fields = *prv == ATM_AFI_E164 ? e164 : code;
114                 for (i = 0; fields[i]; i++) {
115                         for (j = fields[i]; j; j--)
116                                 seq_printf(seq, "%02X", *prv++);
117                         if (fields[i+1]) 
118                                 seq_putc(seq, '.');
119                 }
120         }
121 }
122 
123 
124 static void atmarp_info(struct seq_file *seq, struct net_device *dev,struct
125                         atmarp_entry *entry, struct clip_vcc *clip_vcc) {
126         unsigned long exp;
127         char buf[17];
128         int svc, llc, off;
129 
130         svc = ((clip_vcc == SEQ_NO_VCC_TOKEN) ||
131                (clip_vcc->vcc->sk->family == AF_ATMSVC));
132 
133         llc = ((clip_vcc == SEQ_NO_VCC_TOKEN) ||
134                (clip_vcc->encap));
135 
136         if (clip_vcc == SEQ_NO_VCC_TOKEN)
137                 exp = entry->neigh->used;
138         else
139                 exp = clip_vcc->last_use;
140 
141         exp = (jiffies - exp) / HZ;
142 
143         seq_printf(seq, "%-6s%-4s%-4s%5ld ",
144                    dev->name,
145                    svc ? "SVC" : "PVC",
146                    llc ? "LLC" : "NULL",
147                    exp);
148 
149         off = snprintf(buf, sizeof(buf)-1, "%d.%d.%d.%d", NIPQUAD(entry->ip));
150         while (off < 16)
151                 buf[off++] = ' ';
152         buf[off] = '\0';
153         seq_printf(seq, "%s", buf);
154 
155         if (clip_vcc == SEQ_NO_VCC_TOKEN) {
156                 if (time_before(jiffies, entry->expires))
157                         seq_printf(seq, "(resolving)\n");
158                 else
159                         seq_printf(seq, "(expired, ref %d)\n",
160                                    atomic_read(&entry->neigh->refcnt));
161         } else if (!svc) {
162                 seq_printf(seq, "%d.%d.%d\n",
163                            clip_vcc->vcc->dev->number,
164                            clip_vcc->vcc->vpi,
165                            clip_vcc->vcc->vci);
166         } else {
167                 svc_addr(seq, &clip_vcc->vcc->remote);
168                 seq_putc(seq, '\n');
169         }
170 }
171 
172 struct clip_seq_state {
173         /* This member must be first. */
174         struct neigh_seq_state ns;
175 
176         /* Local to clip specific iteration. */
177         struct clip_vcc *vcc;
178 };
179 
180 static struct clip_vcc *clip_seq_next_vcc(struct atmarp_entry *e,
181                                           struct clip_vcc *curr)
182 {
183         if (!curr) {
184                 curr = e->vccs;
185                 if (!curr)
186                         return SEQ_NO_VCC_TOKEN;
187                 return curr;
188         }
189 
190         if (curr == SEQ_NO_VCC_TOKEN)
191                 return NULL;
192 
193         curr = curr->next;
194 
195         return curr;
196 }
197 
198 static void *clip_seq_vcc_walk(struct clip_seq_state *state,
199                                struct atmarp_entry *e, loff_t *pos)
200 {
201         struct clip_vcc *vcc = state->vcc;
202 
203         vcc = clip_seq_next_vcc(e, vcc);
204         if (vcc && pos != NULL) {
205                 while (*pos) {
206                         vcc = clip_seq_next_vcc(e, vcc);
207                         if (!vcc)
208                                 break;
209                         --(*pos);
210                 }
211         }
212         state->vcc = vcc;
213 
214         return vcc;
215 }
216 
217 static void *clip_seq_sub_iter(struct neigh_seq_state *_state,
218                                struct neighbour *n, loff_t *pos)
219 {
220         struct clip_seq_state *state = (struct clip_seq_state *) _state;
221 
222         return clip_seq_vcc_walk(state, NEIGH2ENTRY(n), pos);
223 }
224 
225 static void *clip_seq_start(struct seq_file *seq, loff_t *pos)
226 {
227         return neigh_seq_start(seq, pos, clip_tbl_hook, NEIGH_SEQ_NEIGH_ONLY);
228 }
229 
230 static int clip_seq_show(struct seq_file *seq, void *v)
231 {
232         static char atm_arp_banner[] = 
233                 "IPitf TypeEncp Idle IP address      ATM address\n";
234 
235         if (v == SEQ_START_TOKEN) {
236                 seq_puts(seq, atm_arp_banner);
237         } else {
238                 struct clip_seq_state *state = seq->private;
239                 struct neighbour *n = v;
240                 struct clip_vcc *vcc = state->vcc;
241 
242                 atmarp_info(seq, n->dev, NEIGH2ENTRY(n), vcc);
243         }
244         return 0;
245 }
246 
247 static struct seq_operations arp_seq_ops = {
248         .start  = clip_seq_start,
249         .next   = neigh_seq_next,
250         .stop   = neigh_seq_stop,
251         .show   = clip_seq_show,
252 };
253 
254 static int arp_seq_open(struct inode *inode, struct file *file)
255 {
256         struct clip_seq_state *state;
257         struct seq_file *seq;
258         int rc = -EAGAIN;
259 
260         if (!clip_tbl_hook)
261                 goto out;
262 
263         state = kmalloc(sizeof(*state), GFP_KERNEL);
264         if (!state) {
265                 rc = -ENOMEM;
266                 goto out_kfree;
267         }
268         memset(state, 0, sizeof(*state));
269         state->ns.neigh_sub_iter = clip_seq_sub_iter;
270 
271         rc = seq_open(file, &arp_seq_ops);
272         if (rc)
273                 goto out_kfree;
274 
275         seq = file->private_data;
276         seq->private = state;
277 out:
278         return rc;
279 
280 out_kfree:
281         kfree(state);
282         goto out;
283 }
284 
285 static struct file_operations arp_seq_fops = {
286         .open           = arp_seq_open,
287         .read           = seq_read,
288         .llseek         = seq_lseek,
289         .release        = seq_release_private,
290         .owner          = THIS_MODULE,
291 };
292 #endif
293 
294 
295 static void pvc_info(struct atm_vcc *vcc, char *buf, int clip_info)
296 {
297         static const char *class_name[] = { "off","UBR","CBR","VBR","ABR" };
298         static const char *aal_name[] = {
299                 "---",  "1",    "2",    "3/4",  /*  0- 3 */
300                 "???",  "5",    "???",  "???",  /*  4- 7 */
301                 "???",  "???",  "???",  "???",  /*  8-11 */
302                 "???",  "",    "???",  "???"}; /* 12-15 */
303         int off;
304 
305         off = sprintf(buf,"%3d %3d %5d %-3s %7d %-5s %7d %-6s",
306             vcc->dev->number,vcc->vpi,vcc->vci,
307             vcc->qos.aal >= sizeof(aal_name)/sizeof(aal_name[0]) ? "err" :
308             aal_name[vcc->qos.aal],vcc->qos.rxtp.min_pcr,
309             class_name[vcc->qos.rxtp.traffic_class],vcc->qos.txtp.min_pcr,
310             class_name[vcc->qos.txtp.traffic_class]);
311 #if defined(CONFIG_ATM_CLIP) || defined(CONFIG_ATM_CLIP_MODULE)
312         if (clip_info && (vcc->push == atm_clip_ops->clip_push)) {
313                 struct clip_vcc *clip_vcc = CLIP_VCC(vcc);
314                 struct net_device *dev;
315 
316                 dev = clip_vcc->entry ? clip_vcc->entry->neigh->dev : NULL;
317                 off += sprintf(buf+off,"CLIP, Itf:%s, Encap:",
318                     dev ? dev->name : "none?");
319                 if (clip_vcc->encap)
320                         off += sprintf(buf+off,"LLC/SNAP");
321                 else
322                         off += sprintf(buf+off,"None");
323         }
324 #endif
325         strcpy(buf+off,"\n");
326 }
327 
328 
329 static const char *vcc_state(struct atm_vcc *vcc)
330 {
331         static const char *map[] = { ATM_VS2TXT_MAP };
332 
333         return map[ATM_VF2VS(vcc->flags)];
334 }
335 
336 
337 static void vc_info(struct atm_vcc *vcc,char *buf)
338 {
339         char *here;
340 
341         here = buf+sprintf(buf,"%p ",vcc);
342         if (!vcc->dev) here += sprintf(here,"Unassigned    ");
343         else here += sprintf(here,"%3d %3d %5d ",vcc->dev->number,vcc->vpi,
344                     vcc->vci);
345         switch (vcc->sk->family) {
346                 case AF_ATMPVC:
347                         here += sprintf(here,"PVC");
348                         break;
349                 case AF_ATMSVC:
350                         here += sprintf(here,"SVC");
351                         break;
352                 default:
353                         here += sprintf(here,"%3d",vcc->sk->family);
354         }
355         here += sprintf(here," %04lx  %5d %7d/%7d %7d/%7d\n",vcc->flags.bits,
356             vcc->reply,
357             atomic_read(&vcc->sk->wmem_alloc),vcc->sk->sndbuf,
358             atomic_read(&vcc->sk->rmem_alloc),vcc->sk->rcvbuf);
359 }
360 
361 
362 static void svc_info(struct atm_vcc *vcc,char *buf)
363 {
364         char *here;
365         int i;
366 
367         if (!vcc->dev)
368                 sprintf(buf,sizeof(void *) == 4 ? "N/A@%p%10s" : "N/A@%p%2s",
369                     vcc,"");
370         else sprintf(buf,"%3d %3d %5d         ",vcc->dev->number,vcc->vpi,
371                     vcc->vci);
372         here = strchr(buf,0);
373         here += sprintf(here,"%-10s ",vcc_state(vcc));
374         here += sprintf(here,"%s%s",vcc->remote.sas_addr.pub,
375             *vcc->remote.sas_addr.pub && *vcc->remote.sas_addr.prv ? "+" : "");
376         if (*vcc->remote.sas_addr.prv)
377                 for (i = 0; i < ATM_ESA_LEN; i++)
378                         here += sprintf(here,"%02x",
379                             vcc->remote.sas_addr.prv[i]);
380         strcat(here,"\n");
381 }
382 
383 
384 #if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE)
385 
386 static char*
387 lec_arp_get_status_string(unsigned char status)
388 {
389   switch(status) {
390   case ESI_UNKNOWN:
391     return "ESI_UNKNOWN       ";
392   case ESI_ARP_PENDING:
393     return "ESI_ARP_PENDING   ";
394   case ESI_VC_PENDING:
395     return "ESI_VC_PENDING    ";
396   case ESI_FLUSH_PENDING:
397     return "ESI_FLUSH_PENDING ";
398   case ESI_FORWARD_DIRECT:
399     return "ESI_FORWARD_DIRECT";
400   default:
401     return "<Unknown>         ";
402   }
403 }
404 
405 static void 
406 lec_info(struct lec_arp_table *entry, char *buf)
407 {
408         int j, offset=0;
409 
410         for(j=0;j<ETH_ALEN;j++) {
411                 offset+=sprintf(buf+offset,"%2.2x",0xff&entry->mac_addr[j]);
412         }
413         offset+=sprintf(buf+offset, " ");
414         for(j=0;j<ATM_ESA_LEN;j++) {
415                 offset+=sprintf(buf+offset,"%2.2x",0xff&entry->atm_addr[j]);
416         }
417         offset+=sprintf(buf+offset, " %s %4.4x",
418                         lec_arp_get_status_string(entry->status),
419                         entry->flags&0xffff);
420         if (entry->vcc) {
421                 offset+=sprintf(buf+offset, "%3d %3d ", entry->vcc->vpi, 
422                                 entry->vcc->vci);                
423         } else
424                 offset+=sprintf(buf+offset, "        ");
425         if (entry->recv_vcc) {
426                 offset+=sprintf(buf+offset, "     %3d %3d", 
427                                 entry->recv_vcc->vpi, entry->recv_vcc->vci);
428         }
429 
430         sprintf(buf+offset,"\n");
431 }
432 
433 #endif
434 
435 static int atm_devices_info(loff_t pos,char *buf)
436 {
437         struct atm_dev *dev;
438         struct list_head *p;
439         int left;
440 
441         if (!pos) {
442                 return sprintf(buf,"Itf Type    ESI/\"MAC\"addr "
443                     "AAL(TX,err,RX,err,drop) ...               [refcnt]\n");
444         }
445         left = pos-1;
446         spin_lock(&atm_dev_lock);
447         list_for_each(p, &atm_devs) {
448                 dev = list_entry(p, struct atm_dev, dev_list);
449                 if (left-- == 0) {
450                         dev_info(dev,buf);
451                         spin_unlock(&atm_dev_lock);
452                         return strlen(buf);
453                 }
454         }
455         spin_unlock(&atm_dev_lock);
456         return 0;
457 }
458 
459 /*
460  * FIXME: it isn't safe to walk the VCC list without turning off interrupts.
461  * What is really needed is some lock on the devices. Ditto for ATMARP.
462  */
463 
464 static int atm_pvc_info(loff_t pos,char *buf)
465 {
466         struct sock *s;
467         struct atm_vcc *vcc;
468         int left, clip_info = 0;
469 
470         if (!pos) {
471                 return sprintf(buf,"Itf VPI VCI   AAL RX(PCR,Class) "
472                     "TX(PCR,Class)\n");
473         }
474         left = pos-1;
475 #if defined(CONFIG_ATM_CLIP) || defined(CONFIG_ATM_CLIP_MODULE)
476         if (try_atm_clip_ops())
477                 clip_info = 1;
478 #endif
479         read_lock(&vcc_sklist_lock);
480         for(s = vcc_sklist; s; s = s->next) {
481                 vcc = s->protinfo.af_atm;
482                 if (vcc->sk->family == PF_ATMPVC && vcc->dev && !left--) {
483                         pvc_info(vcc,buf,clip_info);
484                         read_unlock(&vcc_sklist_lock);
485 #if defined(CONFIG_ATM_CLIP) || defined(CONFIG_ATM_CLIP_MODULE)
486                         if (clip_info && atm_clip_ops->owner)
487                                 __MOD_DEC_USE_COUNT(atm_clip_ops->owner);
488 #endif
489                         return strlen(buf);
490                 }
491         }
492         read_unlock(&vcc_sklist_lock);
493 #if defined(CONFIG_ATM_CLIP) || defined(CONFIG_ATM_CLIP_MODULE)
494         if (clip_info && atm_clip_ops->owner)
495                         __MOD_DEC_USE_COUNT(atm_clip_ops->owner);
496 #endif
497         return 0;
498 }
499 
500 
501 static int atm_vc_info(loff_t pos,char *buf)
502 {
503         struct atm_vcc *vcc;
504         struct sock *s;
505         int left;
506 
507         if (!pos)
508                 return sprintf(buf,sizeof(void *) == 4 ? "%-8s%s" : "%-16s%s",
509                     "Address"," Itf VPI VCI   Fam Flags Reply Send buffer"
510                     "     Recv buffer\n");
511         left = pos-1;
512         read_lock(&vcc_sklist_lock);
513         for(s = vcc_sklist; s; s = s->next) {
514                 vcc = s->protinfo.af_atm;
515                 if (!left--) {
516                         vc_info(vcc,buf);
517                         read_unlock(&vcc_sklist_lock);
518                         return strlen(buf);
519                 }
520         }
521         read_unlock(&vcc_sklist_lock);
522 
523         return 0;
524 }
525 
526 
527 static int atm_svc_info(loff_t pos,char *buf)
528 {
529         struct sock *s;
530         struct atm_vcc *vcc;
531         int left;
532 
533         if (!pos)
534                 return sprintf(buf,"Itf VPI VCI           State      Remote\n");
535         left = pos-1;
536         read_lock(&vcc_sklist_lock);
537         for(s = vcc_sklist; s; s = s->next) {
538                 vcc = s->protinfo.af_atm;
539                 if (vcc->sk->family == PF_ATMSVC && !left--) {
540                         svc_info(vcc,buf);
541                         read_unlock(&vcc_sklist_lock);
542                         return strlen(buf);
543                 }
544         }
545         read_unlock(&vcc_sklist_lock);
546 
547         return 0;
548 }
549 
550 #if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE)
551 static int atm_lec_info(loff_t pos,char *buf)
552 {
553         unsigned long flags;
554         struct lec_priv *priv;
555         struct lec_arp_table *entry;
556         int i, count, d, e;
557         struct net_device *dev;
558 
559         if (!pos) {
560                 return sprintf(buf,"Itf  MAC          ATM destination"
561                     "                          Status            Flags "
562                     "VPI/VCI Recv VPI/VCI\n");
563         }
564         if (!try_atm_lane_ops())
565                 return 0; /* the lane module is not there yet */
566 
567         count = pos;
568         for(d = 0; d < MAX_LEC_ITF; d++) {
569                 dev = atm_lane_ops->get_lec(d);
570                 if (!dev || !(priv = (struct lec_priv *) dev->priv))
571                         continue;
572                 spin_lock_irqsave(&priv->lec_arp_lock, flags);
573                 for(i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
574                         for(entry = priv->lec_arp_tables[i]; entry; entry = entry->next) {
575                                 if (--count)
576                                         continue;
577                                 e = sprintf(buf,"%s ", dev->name);
578                                 lec_info(entry, buf+e);
579                                 spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
580                                 dev_put(dev);
581                                 if (atm_lane_ops->owner)
582                                         __MOD_DEC_USE_COUNT(atm_lane_ops->owner);
583                                 return strlen(buf);
584                         }
585                 }
586                 for(entry = priv->lec_arp_empty_ones; entry; entry = entry->next) {
587                         if (--count)
588                                 continue;
589                         e = sprintf(buf,"%s ", dev->name);
590                         lec_info(entry, buf+e);
591                         spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
592                         dev_put(dev);
593                         if (atm_lane_ops->owner)
594                                 __MOD_DEC_USE_COUNT(atm_lane_ops->owner);
595                         return strlen(buf);
596                 }
597                 for(entry = priv->lec_no_forward; entry; entry=entry->next) {
598                         if (--count)
599                                 continue;
600                         e = sprintf(buf,"%s ", dev->name);
601                         lec_info(entry, buf+e);
602                         spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
603                         dev_put(dev);
604                         if (atm_lane_ops->owner)
605                                 __MOD_DEC_USE_COUNT(atm_lane_ops->owner);
606                         return strlen(buf);
607                 }
608                 for(entry = priv->mcast_fwds; entry; entry = entry->next) {
609                         if (--count)
610                                 continue;
611                         e = sprintf(buf,"%s ", dev->name);
612                         lec_info(entry, buf+e);
613                         spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
614                         dev_put(dev);
615                         if (atm_lane_ops->owner)
616                                 __MOD_DEC_USE_COUNT(atm_lane_ops->owner);
617                         return strlen(buf);
618                 }
619                 spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
620                 dev_put(dev);
621         }
622         if (atm_lane_ops->owner)
623                 __MOD_DEC_USE_COUNT(atm_lane_ops->owner);
624         return 0;
625 }
626 #endif
627 
628 
629 static ssize_t proc_dev_atm_read(struct file *file,char *buf,size_t count,
630     loff_t *pos)
631 {
632         struct atm_dev *dev;
633         unsigned long page;
634         int length;
635 
636         if (count == 0) return 0;
637         page = get_free_page(GFP_KERNEL);
638         if (!page) return -ENOMEM;
639         dev = ((struct proc_dir_entry *) file->f_dentry->d_inode->u.generic_ip)
640             ->data;
641         if (!dev->ops->proc_read)
642                 length = -EINVAL;
643         else {
644                 length = dev->ops->proc_read(dev,pos,(char *) page);
645                 if (length > count) length = -EINVAL;
646         }
647         if (length >= 0) {
648                 if (copy_to_user(buf,(char *) page,length)) length = -EFAULT;
649                 (*pos)++;
650         }
651         free_page(page);
652         return length;
653 }
654 
655 
656 static ssize_t proc_spec_atm_read(struct file *file,char *buf,size_t count,
657     loff_t *pos)
658 {
659         unsigned long page;
660         int length;
661         int (*info)(loff_t,char *);
662         info = ((struct proc_dir_entry *) file->f_dentry->d_inode->u.generic_ip)
663             ->data;
664 
665         if (count == 0) return 0;
666         page = get_free_page(GFP_KERNEL);
667         if (!page) return -ENOMEM;
668         length = (*info)(*pos,(char *) page);
669         if (length > count) length = -EINVAL;
670         if (length >= 0) {
671                 if (copy_to_user(buf,(char *) page,length)) length = -EFAULT;
672                 (*pos)++;
673         }
674         free_page(page);
675         return length;
676 }
677 
678 
679 struct proc_dir_entry *atm_proc_root;
680 EXPORT_SYMBOL(atm_proc_root);
681 
682 
683 int atm_proc_dev_register(struct atm_dev *dev)
684 {
685         int digits,num;
686         int error;
687 
688         error = -ENOMEM;
689         digits = 0;
690         for (num = dev->number; num; num /= 10) digits++;
691         if (!digits) digits++;
692 
693         dev->proc_name = kmalloc(strlen(dev->type) + digits + 2, GFP_ATOMIC);
694         if (!dev->proc_name)
695                 goto fail1;
696         sprintf(dev->proc_name,"%s:%d",dev->type, dev->number);
697 
698         dev->proc_entry = create_proc_entry(dev->proc_name, 0, atm_proc_root);
699         if (!dev->proc_entry)
700                 goto fail0;
701         dev->proc_entry->data = dev;
702         dev->proc_entry->proc_fops = &proc_dev_atm_operations;
703         dev->proc_entry->owner = THIS_MODULE;
704         return 0;
705 fail0:
706         kfree(dev->proc_name);
707 fail1:
708         return error;
709 }
710 
711 
712 void atm_proc_dev_deregister(struct atm_dev *dev)
713 {
714         remove_proc_entry(dev->proc_name, atm_proc_root);
715         kfree(dev->proc_name);
716 }
717 
718 
719 #define CREATE_ENTRY(name) \
720     name = create_proc_entry(#name,0,atm_proc_root); \
721     if (!name) goto cleanup; \
722     name->data = atm_##name##_info; \
723     name->proc_fops = &proc_spec_atm_operations; \
724     name->owner = THIS_MODULE
725 
726 static struct proc_dir_entry *devices = NULL, *pvc = NULL,
727                 *svc = NULL, *arp = NULL, *lec = NULL, *vc = NULL;
728 
729 static void atm_proc_cleanup(void)
730 {
731         if (devices)
732                 remove_proc_entry("devices",atm_proc_root);
733         if (pvc)
734                 remove_proc_entry("pvc",atm_proc_root);
735         if (svc)
736                 remove_proc_entry("svc",atm_proc_root);
737         if (arp)
738                 remove_proc_entry("arp",atm_proc_root);
739         if (lec)
740                 remove_proc_entry("lec",atm_proc_root);
741         if (vc)
742                 remove_proc_entry("vc",atm_proc_root);
743         remove_proc_entry("net/atm",NULL);
744 }
745 
746 int atm_proc_init(void)
747 {
748         atm_proc_root = proc_mkdir("net/atm",NULL);
749         if (!atm_proc_root)
750                 return -ENOMEM;
751         CREATE_ENTRY(devices);
752         CREATE_ENTRY(pvc);
753         CREATE_ENTRY(svc);
754         CREATE_ENTRY(vc);
755 #if defined(CONFIG_ATM_CLIP) || defined(CONFIG_ATM_CLIP_MODULE)
756         arp  = create_proc_entry("arp", S_IRUGO, atm_proc_root);
757         if (!arp)
758                 goto cleanup;
759         arp->proc_fops = &arp_seq_fops;
760 #endif
761 #if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE)
762         CREATE_ENTRY(lec);
763 #endif
764         return 0;
765 
766 cleanup:
767         atm_proc_cleanup();
768         return -ENOMEM;
769 }
770 
771 void atm_proc_exit(void)
772 {
773         atm_proc_cleanup();
774 }
775 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp