/* net/atm/proc.c - ATM /proc interface */
|
/* net/atm/proc.c - ATM /proc interface */
|
|
|
/* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */
|
/* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */
|
|
|
/*
|
/*
|
* The mechanism used here isn't designed for speed but rather for convenience
|
* The mechanism used here isn't designed for speed but rather for convenience
|
* of implementation. We only return one entry per read system call, so we can
|
* of implementation. We only return one entry per read system call, so we can
|
* be reasonably sure not to overrun the page and race conditions may lead to
|
* be reasonably sure not to overrun the page and race conditions may lead to
|
* the addition or omission of some lines but never to any corruption of a
|
* the addition or omission of some lines but never to any corruption of a
|
* line's internal structure.
|
* line's internal structure.
|
*
|
*
|
* Making the whole thing slightly more efficient is left as an exercise to the
|
* Making the whole thing slightly more efficient is left as an exercise to the
|
* reader. (Suggestions: wrapper which loops to get several entries per system
|
* reader. (Suggestions: wrapper which loops to get several entries per system
|
* call; or make --left slightly more clever to avoid O(n^2) characteristics.)
|
* call; or make --left slightly more clever to avoid O(n^2) characteristics.)
|
* I find it fast enough on my unloaded 266 MHz Pentium 2 :-)
|
* I find it fast enough on my unloaded 266 MHz Pentium 2 :-)
|
*/
|
*/
|
|
|
|
|
#include <linux/config.h>
|
#include <linux/config.h>
|
#include <linux/module.h> /* for EXPORT_SYMBOL */
|
#include <linux/module.h> /* for EXPORT_SYMBOL */
|
#include <linux/string.h>
|
#include <linux/string.h>
|
#include <linux/types.h>
|
#include <linux/types.h>
|
#include <linux/mm.h>
|
#include <linux/mm.h>
|
#include <linux/fs.h>
|
#include <linux/fs.h>
|
#include <linux/stat.h>
|
#include <linux/stat.h>
|
#include <linux/proc_fs.h>
|
#include <linux/proc_fs.h>
|
#include <linux/errno.h>
|
#include <linux/errno.h>
|
#include <linux/atm.h>
|
#include <linux/atm.h>
|
#include <linux/atmdev.h>
|
#include <linux/atmdev.h>
|
#include <linux/netdevice.h>
|
#include <linux/netdevice.h>
|
#include <linux/atmclip.h>
|
#include <linux/atmclip.h>
|
#include <linux/atmarp.h>
|
#include <linux/atmarp.h>
|
#include <linux/if_arp.h>
|
#include <linux/if_arp.h>
|
#include <linux/init.h> /* for __init */
|
#include <linux/init.h> /* for __init */
|
#include <asm/uaccess.h>
|
#include <asm/uaccess.h>
|
#include <asm/atomic.h>
|
#include <asm/atomic.h>
|
#include <asm/param.h> /* for HZ */
|
#include <asm/param.h> /* for HZ */
|
#include "resources.h"
|
#include "resources.h"
|
#include "common.h" /* atm_proc_init prototype */
|
#include "common.h" /* atm_proc_init prototype */
|
#include "signaling.h" /* to get sigd - ugly too */
|
#include "signaling.h" /* to get sigd - ugly too */
|
|
|
#if defined(CONFIG_ATM_CLIP) || defined(CONFIG_ATM_CLIP_MODULE)
|
#if defined(CONFIG_ATM_CLIP) || defined(CONFIG_ATM_CLIP_MODULE)
|
#include <net/atmclip.h>
|
#include <net/atmclip.h>
|
#include "ipcommon.h"
|
#include "ipcommon.h"
|
#endif
|
#endif
|
|
|
#if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE)
|
#if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE)
|
#include "lec.h"
|
#include "lec.h"
|
#include "lec_arpc.h"
|
#include "lec_arpc.h"
|
#endif
|
#endif
|
|
|
static ssize_t proc_dev_atm_read(struct file *file,char *buf,size_t count,
|
static ssize_t proc_dev_atm_read(struct file *file,char *buf,size_t count,
|
loff_t *pos);
|
loff_t *pos);
|
static ssize_t proc_spec_atm_read(struct file *file,char *buf,size_t count,
|
static ssize_t proc_spec_atm_read(struct file *file,char *buf,size_t count,
|
loff_t *pos);
|
loff_t *pos);
|
|
|
static struct file_operations proc_dev_atm_operations = {
|
static struct file_operations proc_dev_atm_operations = {
|
read: proc_dev_atm_read,
|
read: proc_dev_atm_read,
|
};
|
};
|
|
|
static struct file_operations proc_spec_atm_operations = {
|
static struct file_operations proc_spec_atm_operations = {
|
read: proc_spec_atm_read,
|
read: proc_spec_atm_read,
|
};
|
};
|
|
|
static void add_stats(char *buf,const char *aal,
|
static void add_stats(char *buf,const char *aal,
|
const struct k_atm_aal_stats *stats)
|
const struct k_atm_aal_stats *stats)
|
{
|
{
|
sprintf(strchr(buf,0),"%s ( %d %d %d %d %d )",aal,
|
sprintf(strchr(buf,0),"%s ( %d %d %d %d %d )",aal,
|
atomic_read(&stats->tx),atomic_read(&stats->tx_err),
|
atomic_read(&stats->tx),atomic_read(&stats->tx_err),
|
atomic_read(&stats->rx),atomic_read(&stats->rx_err),
|
atomic_read(&stats->rx),atomic_read(&stats->rx_err),
|
atomic_read(&stats->rx_drop));
|
atomic_read(&stats->rx_drop));
|
}
|
}
|
|
|
|
|
static void dev_info(const struct atm_dev *dev,char *buf)
|
static void dev_info(const struct atm_dev *dev,char *buf)
|
{
|
{
|
int off,i;
|
int off,i;
|
|
|
off = sprintf(buf,"%3d %-8s",dev->number,dev->type);
|
off = sprintf(buf,"%3d %-8s",dev->number,dev->type);
|
for (i = 0; i < ESI_LEN; i++)
|
for (i = 0; i < ESI_LEN; i++)
|
off += sprintf(buf+off,"%02x",dev->esi[i]);
|
off += sprintf(buf+off,"%02x",dev->esi[i]);
|
strcat(buf," ");
|
strcat(buf," ");
|
add_stats(buf,"0",&dev->stats.aal0);
|
add_stats(buf,"0",&dev->stats.aal0);
|
strcat(buf," ");
|
strcat(buf," ");
|
add_stats(buf,"5",&dev->stats.aal5);
|
add_stats(buf,"5",&dev->stats.aal5);
|
sprintf(strchr(buf,0), "\t[%d]", atomic_read(&dev->refcnt));
|
sprintf(strchr(buf,0), "\t[%d]", atomic_read(&dev->refcnt));
|
strcat(buf,"\n");
|
strcat(buf,"\n");
|
}
|
}
|
|
|
|
|
#if defined(CONFIG_ATM_CLIP) || defined(CONFIG_ATM_CLIP_MODULE)
|
#if defined(CONFIG_ATM_CLIP) || defined(CONFIG_ATM_CLIP_MODULE)
|
|
|
|
|
static int svc_addr(char *buf,struct sockaddr_atmsvc *addr)
|
static int svc_addr(char *buf,struct sockaddr_atmsvc *addr)
|
{
|
{
|
static int code[] = { 1,2,10,6,1,0 };
|
static int code[] = { 1,2,10,6,1,0 };
|
static int e164[] = { 1,8,4,6,1,0 };
|
static int e164[] = { 1,8,4,6,1,0 };
|
int *fields;
|
int *fields;
|
int len,i,j,pos;
|
int len,i,j,pos;
|
|
|
len = 0;
|
len = 0;
|
if (*addr->sas_addr.pub) {
|
if (*addr->sas_addr.pub) {
|
strcpy(buf,addr->sas_addr.pub);
|
strcpy(buf,addr->sas_addr.pub);
|
len = strlen(addr->sas_addr.pub);
|
len = strlen(addr->sas_addr.pub);
|
buf += len;
|
buf += len;
|
if (*addr->sas_addr.prv) {
|
if (*addr->sas_addr.prv) {
|
*buf++ = '+';
|
*buf++ = '+';
|
len++;
|
len++;
|
}
|
}
|
}
|
}
|
else if (!*addr->sas_addr.prv) {
|
else if (!*addr->sas_addr.prv) {
|
strcpy(buf,"(none)");
|
strcpy(buf,"(none)");
|
return strlen(buf);
|
return strlen(buf);
|
}
|
}
|
if (*addr->sas_addr.prv) {
|
if (*addr->sas_addr.prv) {
|
len += 44;
|
len += 44;
|
pos = 0;
|
pos = 0;
|
fields = *addr->sas_addr.prv == ATM_AFI_E164 ? e164 : code;
|
fields = *addr->sas_addr.prv == ATM_AFI_E164 ? e164 : code;
|
for (i = 0; fields[i]; i++) {
|
for (i = 0; fields[i]; i++) {
|
for (j = fields[i]; j; j--) {
|
for (j = fields[i]; j; j--) {
|
sprintf(buf,"%02X",addr->sas_addr.prv[pos++]);
|
sprintf(buf,"%02X",addr->sas_addr.prv[pos++]);
|
buf += 2;
|
buf += 2;
|
}
|
}
|
if (fields[i+1]) *buf++ = '.';
|
if (fields[i+1]) *buf++ = '.';
|
}
|
}
|
}
|
}
|
return len;
|
return len;
|
}
|
}
|
|
|
|
|
static void atmarp_info(struct net_device *dev,struct atmarp_entry *entry,
|
static void atmarp_info(struct net_device *dev,struct atmarp_entry *entry,
|
struct clip_vcc *clip_vcc,char *buf)
|
struct clip_vcc *clip_vcc,char *buf)
|
{
|
{
|
unsigned char *ip;
|
unsigned char *ip;
|
int svc,off,ip_len;
|
int svc,off,ip_len;
|
|
|
svc = !clip_vcc || clip_vcc->vcc->sk->family == AF_ATMSVC;
|
svc = !clip_vcc || clip_vcc->vcc->sk->family == AF_ATMSVC;
|
off = sprintf(buf,"%-6s%-4s%-4s%5ld ",dev->name,svc ? "SVC" : "PVC",
|
off = sprintf(buf,"%-6s%-4s%-4s%5ld ",dev->name,svc ? "SVC" : "PVC",
|
!clip_vcc || clip_vcc->encap ? "LLC" : "NULL",
|
!clip_vcc || clip_vcc->encap ? "LLC" : "NULL",
|
(jiffies-(clip_vcc ? clip_vcc->last_use : entry->neigh->used))/
|
(jiffies-(clip_vcc ? clip_vcc->last_use : entry->neigh->used))/
|
HZ);
|
HZ);
|
ip = (unsigned char *) &entry->ip;
|
ip = (unsigned char *) &entry->ip;
|
ip_len = sprintf(buf+off,"%d.%d.%d.%d",ip[0],ip[1],ip[2],ip[3]);
|
ip_len = sprintf(buf+off,"%d.%d.%d.%d",ip[0],ip[1],ip[2],ip[3]);
|
off += ip_len;
|
off += ip_len;
|
while (ip_len++ < 16) buf[off++] = ' ';
|
while (ip_len++ < 16) buf[off++] = ' ';
|
if (!clip_vcc)
|
if (!clip_vcc)
|
if (time_before(jiffies, entry->expires))
|
if (time_before(jiffies, entry->expires))
|
strcpy(buf+off,"(resolving)\n");
|
strcpy(buf+off,"(resolving)\n");
|
else sprintf(buf+off,"(expired, ref %d)\n",
|
else sprintf(buf+off,"(expired, ref %d)\n",
|
atomic_read(&entry->neigh->refcnt));
|
atomic_read(&entry->neigh->refcnt));
|
else if (!svc)
|
else if (!svc)
|
sprintf(buf+off,"%d.%d.%d\n",clip_vcc->vcc->dev->number,
|
sprintf(buf+off,"%d.%d.%d\n",clip_vcc->vcc->dev->number,
|
clip_vcc->vcc->vpi,clip_vcc->vcc->vci);
|
clip_vcc->vcc->vpi,clip_vcc->vcc->vci);
|
else {
|
else {
|
off += svc_addr(buf+off,&clip_vcc->vcc->remote);
|
off += svc_addr(buf+off,&clip_vcc->vcc->remote);
|
strcpy(buf+off,"\n");
|
strcpy(buf+off,"\n");
|
}
|
}
|
}
|
}
|
|
|
|
|
#endif
|
#endif
|
|
|
|
|
static void pvc_info(struct atm_vcc *vcc, char *buf, int clip_info)
|
static void pvc_info(struct atm_vcc *vcc, char *buf, int clip_info)
|
{
|
{
|
static const char *class_name[] = { "off","UBR","CBR","VBR","ABR" };
|
static const char *class_name[] = { "off","UBR","CBR","VBR","ABR" };
|
static const char *aal_name[] = {
|
static const char *aal_name[] = {
|
"---", "1", "2", "3/4", /* 0- 3 */
|
"---", "1", "2", "3/4", /* 0- 3 */
|
"???", "5", "???", "???", /* 4- 7 */
|
"???", "5", "???", "???", /* 4- 7 */
|
"???", "???", "???", "???", /* 8-11 */
|
"???", "???", "???", "???", /* 8-11 */
|
"???", "0", "???", "???"}; /* 12-15 */
|
"???", "0", "???", "???"}; /* 12-15 */
|
int off;
|
int off;
|
|
|
off = sprintf(buf,"%3d %3d %5d %-3s %7d %-5s %7d %-6s",
|
off = sprintf(buf,"%3d %3d %5d %-3s %7d %-5s %7d %-6s",
|
vcc->dev->number,vcc->vpi,vcc->vci,
|
vcc->dev->number,vcc->vpi,vcc->vci,
|
vcc->qos.aal >= sizeof(aal_name)/sizeof(aal_name[0]) ? "err" :
|
vcc->qos.aal >= sizeof(aal_name)/sizeof(aal_name[0]) ? "err" :
|
aal_name[vcc->qos.aal],vcc->qos.rxtp.min_pcr,
|
aal_name[vcc->qos.aal],vcc->qos.rxtp.min_pcr,
|
class_name[vcc->qos.rxtp.traffic_class],vcc->qos.txtp.min_pcr,
|
class_name[vcc->qos.rxtp.traffic_class],vcc->qos.txtp.min_pcr,
|
class_name[vcc->qos.txtp.traffic_class]);
|
class_name[vcc->qos.txtp.traffic_class]);
|
#if defined(CONFIG_ATM_CLIP) || defined(CONFIG_ATM_CLIP_MODULE)
|
#if defined(CONFIG_ATM_CLIP) || defined(CONFIG_ATM_CLIP_MODULE)
|
if (clip_info && (vcc->push == atm_clip_ops->clip_push)) {
|
if (clip_info && (vcc->push == atm_clip_ops->clip_push)) {
|
struct clip_vcc *clip_vcc = CLIP_VCC(vcc);
|
struct clip_vcc *clip_vcc = CLIP_VCC(vcc);
|
struct net_device *dev;
|
struct net_device *dev;
|
|
|
dev = clip_vcc->entry ? clip_vcc->entry->neigh->dev : NULL;
|
dev = clip_vcc->entry ? clip_vcc->entry->neigh->dev : NULL;
|
off += sprintf(buf+off,"CLIP, Itf:%s, Encap:",
|
off += sprintf(buf+off,"CLIP, Itf:%s, Encap:",
|
dev ? dev->name : "none?");
|
dev ? dev->name : "none?");
|
if (clip_vcc->encap)
|
if (clip_vcc->encap)
|
off += sprintf(buf+off,"LLC/SNAP");
|
off += sprintf(buf+off,"LLC/SNAP");
|
else
|
else
|
off += sprintf(buf+off,"None");
|
off += sprintf(buf+off,"None");
|
}
|
}
|
#endif
|
#endif
|
strcpy(buf+off,"\n");
|
strcpy(buf+off,"\n");
|
}
|
}
|
|
|
|
|
static const char *vcc_state(struct atm_vcc *vcc)
|
static const char *vcc_state(struct atm_vcc *vcc)
|
{
|
{
|
static const char *map[] = { ATM_VS2TXT_MAP };
|
static const char *map[] = { ATM_VS2TXT_MAP };
|
|
|
return map[ATM_VF2VS(vcc->flags)];
|
return map[ATM_VF2VS(vcc->flags)];
|
}
|
}
|
|
|
|
|
static void vc_info(struct atm_vcc *vcc,char *buf)
|
static void vc_info(struct atm_vcc *vcc,char *buf)
|
{
|
{
|
char *here;
|
char *here;
|
|
|
here = buf+sprintf(buf,"%p ",vcc);
|
here = buf+sprintf(buf,"%p ",vcc);
|
if (!vcc->dev) here += sprintf(here,"Unassigned ");
|
if (!vcc->dev) here += sprintf(here,"Unassigned ");
|
else here += sprintf(here,"%3d %3d %5d ",vcc->dev->number,vcc->vpi,
|
else here += sprintf(here,"%3d %3d %5d ",vcc->dev->number,vcc->vpi,
|
vcc->vci);
|
vcc->vci);
|
switch (vcc->sk->family) {
|
switch (vcc->sk->family) {
|
case AF_ATMPVC:
|
case AF_ATMPVC:
|
here += sprintf(here,"PVC");
|
here += sprintf(here,"PVC");
|
break;
|
break;
|
case AF_ATMSVC:
|
case AF_ATMSVC:
|
here += sprintf(here,"SVC");
|
here += sprintf(here,"SVC");
|
break;
|
break;
|
default:
|
default:
|
here += sprintf(here,"%3d",vcc->sk->family);
|
here += sprintf(here,"%3d",vcc->sk->family);
|
}
|
}
|
here += sprintf(here," %04lx %5d %7d/%7d %7d/%7d\n",vcc->flags.bits,
|
here += sprintf(here," %04lx %5d %7d/%7d %7d/%7d\n",vcc->flags.bits,
|
vcc->reply,
|
vcc->reply,
|
atomic_read(&vcc->sk->wmem_alloc),vcc->sk->sndbuf,
|
atomic_read(&vcc->sk->wmem_alloc),vcc->sk->sndbuf,
|
atomic_read(&vcc->sk->rmem_alloc),vcc->sk->rcvbuf);
|
atomic_read(&vcc->sk->rmem_alloc),vcc->sk->rcvbuf);
|
}
|
}
|
|
|
|
|
static void svc_info(struct atm_vcc *vcc,char *buf)
|
static void svc_info(struct atm_vcc *vcc,char *buf)
|
{
|
{
|
char *here;
|
char *here;
|
int i;
|
int i;
|
|
|
if (!vcc->dev)
|
if (!vcc->dev)
|
sprintf(buf,sizeof(void *) == 4 ? "N/A@%p%10s" : "N/A@%p%2s",
|
sprintf(buf,sizeof(void *) == 4 ? "N/A@%p%10s" : "N/A@%p%2s",
|
vcc,"");
|
vcc,"");
|
else sprintf(buf,"%3d %3d %5d ",vcc->dev->number,vcc->vpi,
|
else sprintf(buf,"%3d %3d %5d ",vcc->dev->number,vcc->vpi,
|
vcc->vci);
|
vcc->vci);
|
here = strchr(buf,0);
|
here = strchr(buf,0);
|
here += sprintf(here,"%-10s ",vcc_state(vcc));
|
here += sprintf(here,"%-10s ",vcc_state(vcc));
|
here += sprintf(here,"%s%s",vcc->remote.sas_addr.pub,
|
here += sprintf(here,"%s%s",vcc->remote.sas_addr.pub,
|
*vcc->remote.sas_addr.pub && *vcc->remote.sas_addr.prv ? "+" : "");
|
*vcc->remote.sas_addr.pub && *vcc->remote.sas_addr.prv ? "+" : "");
|
if (*vcc->remote.sas_addr.prv)
|
if (*vcc->remote.sas_addr.prv)
|
for (i = 0; i < ATM_ESA_LEN; i++)
|
for (i = 0; i < ATM_ESA_LEN; i++)
|
here += sprintf(here,"%02x",
|
here += sprintf(here,"%02x",
|
vcc->remote.sas_addr.prv[i]);
|
vcc->remote.sas_addr.prv[i]);
|
strcat(here,"\n");
|
strcat(here,"\n");
|
}
|
}
|
|
|
|
|
#if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE)
|
#if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE)
|
|
|
static char*
|
static char*
|
lec_arp_get_status_string(unsigned char status)
|
lec_arp_get_status_string(unsigned char status)
|
{
|
{
|
switch(status) {
|
switch(status) {
|
case ESI_UNKNOWN:
|
case ESI_UNKNOWN:
|
return "ESI_UNKNOWN ";
|
return "ESI_UNKNOWN ";
|
case ESI_ARP_PENDING:
|
case ESI_ARP_PENDING:
|
return "ESI_ARP_PENDING ";
|
return "ESI_ARP_PENDING ";
|
case ESI_VC_PENDING:
|
case ESI_VC_PENDING:
|
return "ESI_VC_PENDING ";
|
return "ESI_VC_PENDING ";
|
case ESI_FLUSH_PENDING:
|
case ESI_FLUSH_PENDING:
|
return "ESI_FLUSH_PENDING ";
|
return "ESI_FLUSH_PENDING ";
|
case ESI_FORWARD_DIRECT:
|
case ESI_FORWARD_DIRECT:
|
return "ESI_FORWARD_DIRECT";
|
return "ESI_FORWARD_DIRECT";
|
default:
|
default:
|
return "<Unknown> ";
|
return "<Unknown> ";
|
}
|
}
|
}
|
}
|
|
|
static void
|
static void
|
lec_info(struct lec_arp_table *entry, char *buf)
|
lec_info(struct lec_arp_table *entry, char *buf)
|
{
|
{
|
int j, offset=0;
|
int j, offset=0;
|
|
|
for(j=0;j<ETH_ALEN;j++) {
|
for(j=0;j<ETH_ALEN;j++) {
|
offset+=sprintf(buf+offset,"%2.2x",0xff&entry->mac_addr[j]);
|
offset+=sprintf(buf+offset,"%2.2x",0xff&entry->mac_addr[j]);
|
}
|
}
|
offset+=sprintf(buf+offset, " ");
|
offset+=sprintf(buf+offset, " ");
|
for(j=0;j<ATM_ESA_LEN;j++) {
|
for(j=0;j<ATM_ESA_LEN;j++) {
|
offset+=sprintf(buf+offset,"%2.2x",0xff&entry->atm_addr[j]);
|
offset+=sprintf(buf+offset,"%2.2x",0xff&entry->atm_addr[j]);
|
}
|
}
|
offset+=sprintf(buf+offset, " %s %4.4x",
|
offset+=sprintf(buf+offset, " %s %4.4x",
|
lec_arp_get_status_string(entry->status),
|
lec_arp_get_status_string(entry->status),
|
entry->flags&0xffff);
|
entry->flags&0xffff);
|
if (entry->vcc) {
|
if (entry->vcc) {
|
offset+=sprintf(buf+offset, "%3d %3d ", entry->vcc->vpi,
|
offset+=sprintf(buf+offset, "%3d %3d ", entry->vcc->vpi,
|
entry->vcc->vci);
|
entry->vcc->vci);
|
} else
|
} else
|
offset+=sprintf(buf+offset, " ");
|
offset+=sprintf(buf+offset, " ");
|
if (entry->recv_vcc) {
|
if (entry->recv_vcc) {
|
offset+=sprintf(buf+offset, " %3d %3d",
|
offset+=sprintf(buf+offset, " %3d %3d",
|
entry->recv_vcc->vpi, entry->recv_vcc->vci);
|
entry->recv_vcc->vpi, entry->recv_vcc->vci);
|
}
|
}
|
|
|
sprintf(buf+offset,"\n");
|
sprintf(buf+offset,"\n");
|
}
|
}
|
|
|
#endif
|
#endif
|
|
|
static int atm_devices_info(loff_t pos,char *buf)
|
static int atm_devices_info(loff_t pos,char *buf)
|
{
|
{
|
struct atm_dev *dev;
|
struct atm_dev *dev;
|
struct list_head *p;
|
struct list_head *p;
|
int left;
|
int left;
|
|
|
if (!pos) {
|
if (!pos) {
|
return sprintf(buf,"Itf Type ESI/\"MAC\"addr "
|
return sprintf(buf,"Itf Type ESI/\"MAC\"addr "
|
"AAL(TX,err,RX,err,drop) ... [refcnt]\n");
|
"AAL(TX,err,RX,err,drop) ... [refcnt]\n");
|
}
|
}
|
left = pos-1;
|
left = pos-1;
|
spin_lock(&atm_dev_lock);
|
spin_lock(&atm_dev_lock);
|
list_for_each(p, &atm_devs) {
|
list_for_each(p, &atm_devs) {
|
dev = list_entry(p, struct atm_dev, dev_list);
|
dev = list_entry(p, struct atm_dev, dev_list);
|
if (left-- == 0) {
|
if (left-- == 0) {
|
dev_info(dev,buf);
|
dev_info(dev,buf);
|
spin_unlock(&atm_dev_lock);
|
spin_unlock(&atm_dev_lock);
|
return strlen(buf);
|
return strlen(buf);
|
}
|
}
|
}
|
}
|
spin_unlock(&atm_dev_lock);
|
spin_unlock(&atm_dev_lock);
|
return 0;
|
return 0;
|
}
|
}
|
|
|
/*
|
/*
|
* FIXME: it isn't safe to walk the VCC list without turning off interrupts.
|
* FIXME: it isn't safe to walk the VCC list without turning off interrupts.
|
* What is really needed is some lock on the devices. Ditto for ATMARP.
|
* What is really needed is some lock on the devices. Ditto for ATMARP.
|
*/
|
*/
|
|
|
static int atm_pvc_info(loff_t pos,char *buf)
|
static int atm_pvc_info(loff_t pos,char *buf)
|
{
|
{
|
struct sock *s;
|
struct sock *s;
|
struct atm_vcc *vcc;
|
struct atm_vcc *vcc;
|
int left, clip_info = 0;
|
int left, clip_info = 0;
|
|
|
if (!pos) {
|
if (!pos) {
|
return sprintf(buf,"Itf VPI VCI AAL RX(PCR,Class) "
|
return sprintf(buf,"Itf VPI VCI AAL RX(PCR,Class) "
|
"TX(PCR,Class)\n");
|
"TX(PCR,Class)\n");
|
}
|
}
|
left = pos-1;
|
left = pos-1;
|
#if defined(CONFIG_ATM_CLIP) || defined(CONFIG_ATM_CLIP_MODULE)
|
#if defined(CONFIG_ATM_CLIP) || defined(CONFIG_ATM_CLIP_MODULE)
|
if (try_atm_clip_ops())
|
if (try_atm_clip_ops())
|
clip_info = 1;
|
clip_info = 1;
|
#endif
|
#endif
|
read_lock(&vcc_sklist_lock);
|
read_lock(&vcc_sklist_lock);
|
for(s = vcc_sklist; s; s = s->next) {
|
for(s = vcc_sklist; s; s = s->next) {
|
vcc = s->protinfo.af_atm;
|
vcc = s->protinfo.af_atm;
|
if (vcc->sk->family == PF_ATMPVC && vcc->dev && !left--) {
|
if (vcc->sk->family == PF_ATMPVC && vcc->dev && !left--) {
|
pvc_info(vcc,buf,clip_info);
|
pvc_info(vcc,buf,clip_info);
|
read_unlock(&vcc_sklist_lock);
|
read_unlock(&vcc_sklist_lock);
|
#if defined(CONFIG_ATM_CLIP) || defined(CONFIG_ATM_CLIP_MODULE)
|
#if defined(CONFIG_ATM_CLIP) || defined(CONFIG_ATM_CLIP_MODULE)
|
if (clip_info && atm_clip_ops->owner)
|
if (clip_info && atm_clip_ops->owner)
|
__MOD_DEC_USE_COUNT(atm_clip_ops->owner);
|
__MOD_DEC_USE_COUNT(atm_clip_ops->owner);
|
#endif
|
#endif
|
return strlen(buf);
|
return strlen(buf);
|
}
|
}
|
}
|
}
|
read_unlock(&vcc_sklist_lock);
|
read_unlock(&vcc_sklist_lock);
|
#if defined(CONFIG_ATM_CLIP) || defined(CONFIG_ATM_CLIP_MODULE)
|
#if defined(CONFIG_ATM_CLIP) || defined(CONFIG_ATM_CLIP_MODULE)
|
if (clip_info && atm_clip_ops->owner)
|
if (clip_info && atm_clip_ops->owner)
|
__MOD_DEC_USE_COUNT(atm_clip_ops->owner);
|
__MOD_DEC_USE_COUNT(atm_clip_ops->owner);
|
#endif
|
#endif
|
return 0;
|
return 0;
|
}
|
}
|
|
|
|
|
static int atm_vc_info(loff_t pos,char *buf)
|
static int atm_vc_info(loff_t pos,char *buf)
|
{
|
{
|
struct atm_vcc *vcc;
|
struct atm_vcc *vcc;
|
struct sock *s;
|
struct sock *s;
|
int left;
|
int left;
|
|
|
if (!pos)
|
if (!pos)
|
return sprintf(buf,sizeof(void *) == 4 ? "%-8s%s" : "%-16s%s",
|
return sprintf(buf,sizeof(void *) == 4 ? "%-8s%s" : "%-16s%s",
|
"Address"," Itf VPI VCI Fam Flags Reply Send buffer"
|
"Address"," Itf VPI VCI Fam Flags Reply Send buffer"
|
" Recv buffer\n");
|
" Recv buffer\n");
|
left = pos-1;
|
left = pos-1;
|
read_lock(&vcc_sklist_lock);
|
read_lock(&vcc_sklist_lock);
|
for(s = vcc_sklist; s; s = s->next) {
|
for(s = vcc_sklist; s; s = s->next) {
|
vcc = s->protinfo.af_atm;
|
vcc = s->protinfo.af_atm;
|
if (!left--) {
|
if (!left--) {
|
vc_info(vcc,buf);
|
vc_info(vcc,buf);
|
read_unlock(&vcc_sklist_lock);
|
read_unlock(&vcc_sklist_lock);
|
return strlen(buf);
|
return strlen(buf);
|
}
|
}
|
}
|
}
|
read_unlock(&vcc_sklist_lock);
|
read_unlock(&vcc_sklist_lock);
|
|
|
return 0;
|
return 0;
|
}
|
}
|
|
|
|
|
static int atm_svc_info(loff_t pos,char *buf)
|
static int atm_svc_info(loff_t pos,char *buf)
|
{
|
{
|
struct sock *s;
|
struct sock *s;
|
struct atm_vcc *vcc;
|
struct atm_vcc *vcc;
|
int left;
|
int left;
|
|
|
if (!pos)
|
if (!pos)
|
return sprintf(buf,"Itf VPI VCI State Remote\n");
|
return sprintf(buf,"Itf VPI VCI State Remote\n");
|
left = pos-1;
|
left = pos-1;
|
read_lock(&vcc_sklist_lock);
|
read_lock(&vcc_sklist_lock);
|
for(s = vcc_sklist; s; s = s->next) {
|
for(s = vcc_sklist; s; s = s->next) {
|
vcc = s->protinfo.af_atm;
|
vcc = s->protinfo.af_atm;
|
if (vcc->sk->family == PF_ATMSVC && !left--) {
|
if (vcc->sk->family == PF_ATMSVC && !left--) {
|
svc_info(vcc,buf);
|
svc_info(vcc,buf);
|
read_unlock(&vcc_sklist_lock);
|
read_unlock(&vcc_sklist_lock);
|
return strlen(buf);
|
return strlen(buf);
|
}
|
}
|
}
|
}
|
read_unlock(&vcc_sklist_lock);
|
read_unlock(&vcc_sklist_lock);
|
|
|
return 0;
|
return 0;
|
}
|
}
|
|
|
#if defined(CONFIG_ATM_CLIP) || defined(CONFIG_ATM_CLIP_MODULE)
|
#if defined(CONFIG_ATM_CLIP) || defined(CONFIG_ATM_CLIP_MODULE)
|
static int atm_arp_info(loff_t pos,char *buf)
|
static int atm_arp_info(loff_t pos,char *buf)
|
{
|
{
|
struct neighbour *n;
|
struct neighbour *n;
|
int i,count;
|
int i,count;
|
|
|
if (!pos) {
|
if (!pos) {
|
return sprintf(buf,"IPitf TypeEncp Idle IP address "
|
return sprintf(buf,"IPitf TypeEncp Idle IP address "
|
"ATM address\n");
|
"ATM address\n");
|
}
|
}
|
if (!try_atm_clip_ops())
|
if (!try_atm_clip_ops())
|
return 0;
|
return 0;
|
count = pos;
|
count = pos;
|
read_lock_bh(&clip_tbl_hook->lock);
|
read_lock_bh(&clip_tbl_hook->lock);
|
for (i = 0; i <= NEIGH_HASHMASK; i++)
|
for (i = 0; i <= NEIGH_HASHMASK; i++)
|
for (n = clip_tbl_hook->hash_buckets[i]; n; n = n->next) {
|
for (n = clip_tbl_hook->hash_buckets[i]; n; n = n->next) {
|
struct atmarp_entry *entry = NEIGH2ENTRY(n);
|
struct atmarp_entry *entry = NEIGH2ENTRY(n);
|
struct clip_vcc *vcc;
|
struct clip_vcc *vcc;
|
|
|
if (!entry->vccs) {
|
if (!entry->vccs) {
|
if (--count) continue;
|
if (--count) continue;
|
atmarp_info(n->dev,entry,NULL,buf);
|
atmarp_info(n->dev,entry,NULL,buf);
|
read_unlock_bh(&clip_tbl_hook->lock);
|
read_unlock_bh(&clip_tbl_hook->lock);
|
if (atm_clip_ops->owner)
|
if (atm_clip_ops->owner)
|
__MOD_DEC_USE_COUNT(atm_clip_ops->owner);
|
__MOD_DEC_USE_COUNT(atm_clip_ops->owner);
|
return strlen(buf);
|
return strlen(buf);
|
}
|
}
|
for (vcc = entry->vccs; vcc;
|
for (vcc = entry->vccs; vcc;
|
vcc = vcc->next) {
|
vcc = vcc->next) {
|
if (--count) continue;
|
if (--count) continue;
|
atmarp_info(n->dev,entry,vcc,buf);
|
atmarp_info(n->dev,entry,vcc,buf);
|
read_unlock_bh(&clip_tbl_hook->lock);
|
read_unlock_bh(&clip_tbl_hook->lock);
|
if (atm_clip_ops->owner)
|
if (atm_clip_ops->owner)
|
__MOD_DEC_USE_COUNT(atm_clip_ops->owner);
|
__MOD_DEC_USE_COUNT(atm_clip_ops->owner);
|
return strlen(buf);
|
return strlen(buf);
|
}
|
}
|
}
|
}
|
read_unlock_bh(&clip_tbl_hook->lock);
|
read_unlock_bh(&clip_tbl_hook->lock);
|
if (atm_clip_ops->owner)
|
if (atm_clip_ops->owner)
|
__MOD_DEC_USE_COUNT(atm_clip_ops->owner);
|
__MOD_DEC_USE_COUNT(atm_clip_ops->owner);
|
return 0;
|
return 0;
|
}
|
}
|
#endif
|
#endif
|
|
|
#if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE)
|
#if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE)
|
static int atm_lec_info(loff_t pos,char *buf)
|
static int atm_lec_info(loff_t pos,char *buf)
|
{
|
{
|
unsigned long flags;
|
unsigned long flags;
|
struct lec_priv *priv;
|
struct lec_priv *priv;
|
struct lec_arp_table *entry;
|
struct lec_arp_table *entry;
|
int i, count, d, e;
|
int i, count, d, e;
|
struct net_device *dev;
|
struct net_device *dev;
|
|
|
if (!pos) {
|
if (!pos) {
|
return sprintf(buf,"Itf MAC ATM destination"
|
return sprintf(buf,"Itf MAC ATM destination"
|
" Status Flags "
|
" Status Flags "
|
"VPI/VCI Recv VPI/VCI\n");
|
"VPI/VCI Recv VPI/VCI\n");
|
}
|
}
|
if (!try_atm_lane_ops())
|
if (!try_atm_lane_ops())
|
return 0; /* the lane module is not there yet */
|
return 0; /* the lane module is not there yet */
|
|
|
count = pos;
|
count = pos;
|
for(d = 0; d < MAX_LEC_ITF; d++) {
|
for(d = 0; d < MAX_LEC_ITF; d++) {
|
dev = atm_lane_ops->get_lec(d);
|
dev = atm_lane_ops->get_lec(d);
|
if (!dev || !(priv = (struct lec_priv *) dev->priv))
|
if (!dev || !(priv = (struct lec_priv *) dev->priv))
|
continue;
|
continue;
|
spin_lock_irqsave(&priv->lec_arp_lock, flags);
|
spin_lock_irqsave(&priv->lec_arp_lock, flags);
|
for(i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
|
for(i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
|
for(entry = priv->lec_arp_tables[i]; entry; entry = entry->next) {
|
for(entry = priv->lec_arp_tables[i]; entry; entry = entry->next) {
|
if (--count)
|
if (--count)
|
continue;
|
continue;
|
e = sprintf(buf,"%s ", dev->name);
|
e = sprintf(buf,"%s ", dev->name);
|
lec_info(entry, buf+e);
|
lec_info(entry, buf+e);
|
spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
|
spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
|
dev_put(dev);
|
dev_put(dev);
|
if (atm_lane_ops->owner)
|
if (atm_lane_ops->owner)
|
__MOD_DEC_USE_COUNT(atm_lane_ops->owner);
|
__MOD_DEC_USE_COUNT(atm_lane_ops->owner);
|
return strlen(buf);
|
return strlen(buf);
|
}
|
}
|
}
|
}
|
for(entry = priv->lec_arp_empty_ones; entry; entry = entry->next) {
|
for(entry = priv->lec_arp_empty_ones; entry; entry = entry->next) {
|
if (--count)
|
if (--count)
|
continue;
|
continue;
|
e = sprintf(buf,"%s ", dev->name);
|
e = sprintf(buf,"%s ", dev->name);
|
lec_info(entry, buf+e);
|
lec_info(entry, buf+e);
|
spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
|
spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
|
dev_put(dev);
|
dev_put(dev);
|
if (atm_lane_ops->owner)
|
if (atm_lane_ops->owner)
|
__MOD_DEC_USE_COUNT(atm_lane_ops->owner);
|
__MOD_DEC_USE_COUNT(atm_lane_ops->owner);
|
return strlen(buf);
|
return strlen(buf);
|
}
|
}
|
for(entry = priv->lec_no_forward; entry; entry=entry->next) {
|
for(entry = priv->lec_no_forward; entry; entry=entry->next) {
|
if (--count)
|
if (--count)
|
continue;
|
continue;
|
e = sprintf(buf,"%s ", dev->name);
|
e = sprintf(buf,"%s ", dev->name);
|
lec_info(entry, buf+e);
|
lec_info(entry, buf+e);
|
spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
|
spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
|
dev_put(dev);
|
dev_put(dev);
|
if (atm_lane_ops->owner)
|
if (atm_lane_ops->owner)
|
__MOD_DEC_USE_COUNT(atm_lane_ops->owner);
|
__MOD_DEC_USE_COUNT(atm_lane_ops->owner);
|
return strlen(buf);
|
return strlen(buf);
|
}
|
}
|
for(entry = priv->mcast_fwds; entry; entry = entry->next) {
|
for(entry = priv->mcast_fwds; entry; entry = entry->next) {
|
if (--count)
|
if (--count)
|
continue;
|
continue;
|
e = sprintf(buf,"%s ", dev->name);
|
e = sprintf(buf,"%s ", dev->name);
|
lec_info(entry, buf+e);
|
lec_info(entry, buf+e);
|
spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
|
spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
|
dev_put(dev);
|
dev_put(dev);
|
if (atm_lane_ops->owner)
|
if (atm_lane_ops->owner)
|
__MOD_DEC_USE_COUNT(atm_lane_ops->owner);
|
__MOD_DEC_USE_COUNT(atm_lane_ops->owner);
|
return strlen(buf);
|
return strlen(buf);
|
}
|
}
|
spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
|
spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
|
dev_put(dev);
|
dev_put(dev);
|
}
|
}
|
if (atm_lane_ops->owner)
|
if (atm_lane_ops->owner)
|
__MOD_DEC_USE_COUNT(atm_lane_ops->owner);
|
__MOD_DEC_USE_COUNT(atm_lane_ops->owner);
|
return 0;
|
return 0;
|
}
|
}
|
#endif
|
#endif
|
|
|
|
|
static ssize_t proc_dev_atm_read(struct file *file,char *buf,size_t count,
|
static ssize_t proc_dev_atm_read(struct file *file,char *buf,size_t count,
|
loff_t *pos)
|
loff_t *pos)
|
{
|
{
|
struct atm_dev *dev;
|
struct atm_dev *dev;
|
unsigned long page;
|
unsigned long page;
|
int length;
|
int length;
|
|
|
if (count == 0) return 0;
|
if (count == 0) return 0;
|
page = get_free_page(GFP_KERNEL);
|
page = get_free_page(GFP_KERNEL);
|
if (!page) return -ENOMEM;
|
if (!page) return -ENOMEM;
|
dev = ((struct proc_dir_entry *) file->f_dentry->d_inode->u.generic_ip)
|
dev = ((struct proc_dir_entry *) file->f_dentry->d_inode->u.generic_ip)
|
->data;
|
->data;
|
if (!dev->ops->proc_read)
|
if (!dev->ops->proc_read)
|
length = -EINVAL;
|
length = -EINVAL;
|
else {
|
else {
|
length = dev->ops->proc_read(dev,pos,(char *) page);
|
length = dev->ops->proc_read(dev,pos,(char *) page);
|
if (length > count) length = -EINVAL;
|
if (length > count) length = -EINVAL;
|
}
|
}
|
if (length >= 0) {
|
if (length >= 0) {
|
if (copy_to_user(buf,(char *) page,length)) length = -EFAULT;
|
if (copy_to_user(buf,(char *) page,length)) length = -EFAULT;
|
(*pos)++;
|
(*pos)++;
|
}
|
}
|
free_page(page);
|
free_page(page);
|
return length;
|
return length;
|
}
|
}
|
|
|
|
|
static ssize_t proc_spec_atm_read(struct file *file,char *buf,size_t count,
|
static ssize_t proc_spec_atm_read(struct file *file,char *buf,size_t count,
|
loff_t *pos)
|
loff_t *pos)
|
{
|
{
|
unsigned long page;
|
unsigned long page;
|
int length;
|
int length;
|
int (*info)(loff_t,char *);
|
int (*info)(loff_t,char *);
|
info = ((struct proc_dir_entry *) file->f_dentry->d_inode->u.generic_ip)
|
info = ((struct proc_dir_entry *) file->f_dentry->d_inode->u.generic_ip)
|
->data;
|
->data;
|
|
|
if (count == 0) return 0;
|
if (count == 0) return 0;
|
page = get_free_page(GFP_KERNEL);
|
page = get_free_page(GFP_KERNEL);
|
if (!page) return -ENOMEM;
|
if (!page) return -ENOMEM;
|
length = (*info)(*pos,(char *) page);
|
length = (*info)(*pos,(char *) page);
|
if (length > count) length = -EINVAL;
|
if (length > count) length = -EINVAL;
|
if (length >= 0) {
|
if (length >= 0) {
|
if (copy_to_user(buf,(char *) page,length)) length = -EFAULT;
|
if (copy_to_user(buf,(char *) page,length)) length = -EFAULT;
|
(*pos)++;
|
(*pos)++;
|
}
|
}
|
free_page(page);
|
free_page(page);
|
return length;
|
return length;
|
}
|
}
|
|
|
|
|
struct proc_dir_entry *atm_proc_root;
|
struct proc_dir_entry *atm_proc_root;
|
EXPORT_SYMBOL(atm_proc_root);
|
EXPORT_SYMBOL(atm_proc_root);
|
|
|
|
|
int atm_proc_dev_register(struct atm_dev *dev)
|
int atm_proc_dev_register(struct atm_dev *dev)
|
{
|
{
|
int digits,num;
|
int digits,num;
|
int error;
|
int error;
|
|
|
error = -ENOMEM;
|
error = -ENOMEM;
|
digits = 0;
|
digits = 0;
|
for (num = dev->number; num; num /= 10) digits++;
|
for (num = dev->number; num; num /= 10) digits++;
|
if (!digits) digits++;
|
if (!digits) digits++;
|
|
|
dev->proc_name = kmalloc(strlen(dev->type) + digits + 2, GFP_ATOMIC);
|
dev->proc_name = kmalloc(strlen(dev->type) + digits + 2, GFP_ATOMIC);
|
if (!dev->proc_name)
|
if (!dev->proc_name)
|
goto fail1;
|
goto fail1;
|
sprintf(dev->proc_name,"%s:%d",dev->type, dev->number);
|
sprintf(dev->proc_name,"%s:%d",dev->type, dev->number);
|
|
|
dev->proc_entry = create_proc_entry(dev->proc_name, 0, atm_proc_root);
|
dev->proc_entry = create_proc_entry(dev->proc_name, 0, atm_proc_root);
|
if (!dev->proc_entry)
|
if (!dev->proc_entry)
|
goto fail0;
|
goto fail0;
|
dev->proc_entry->data = dev;
|
dev->proc_entry->data = dev;
|
dev->proc_entry->proc_fops = &proc_dev_atm_operations;
|
dev->proc_entry->proc_fops = &proc_dev_atm_operations;
|
dev->proc_entry->owner = THIS_MODULE;
|
dev->proc_entry->owner = THIS_MODULE;
|
return 0;
|
return 0;
|
fail0:
|
fail0:
|
kfree(dev->proc_name);
|
kfree(dev->proc_name);
|
fail1:
|
fail1:
|
return error;
|
return error;
|
}
|
}
|
|
|
|
|
void atm_proc_dev_deregister(struct atm_dev *dev)
|
void atm_proc_dev_deregister(struct atm_dev *dev)
|
{
|
{
|
remove_proc_entry(dev->proc_name, atm_proc_root);
|
remove_proc_entry(dev->proc_name, atm_proc_root);
|
kfree(dev->proc_name);
|
kfree(dev->proc_name);
|
}
|
}
|
|
|
|
|
#define CREATE_ENTRY(name) \
|
#define CREATE_ENTRY(name) \
|
name = create_proc_entry(#name,0,atm_proc_root); \
|
name = create_proc_entry(#name,0,atm_proc_root); \
|
if (!name) goto cleanup; \
|
if (!name) goto cleanup; \
|
name->data = atm_##name##_info; \
|
name->data = atm_##name##_info; \
|
name->proc_fops = &proc_spec_atm_operations; \
|
name->proc_fops = &proc_spec_atm_operations; \
|
name->owner = THIS_MODULE
|
name->owner = THIS_MODULE
|
|
|
static struct proc_dir_entry *devices = NULL, *pvc = NULL,
|
static struct proc_dir_entry *devices = NULL, *pvc = NULL,
|
*svc = NULL, *arp = NULL, *lec = NULL, *vc = NULL;
|
*svc = NULL, *arp = NULL, *lec = NULL, *vc = NULL;
|
|
|
static void atm_proc_cleanup(void)
|
static void atm_proc_cleanup(void)
|
{
|
{
|
if (devices)
|
if (devices)
|
remove_proc_entry("devices",atm_proc_root);
|
remove_proc_entry("devices",atm_proc_root);
|
if (pvc)
|
if (pvc)
|
remove_proc_entry("pvc",atm_proc_root);
|
remove_proc_entry("pvc",atm_proc_root);
|
if (svc)
|
if (svc)
|
remove_proc_entry("svc",atm_proc_root);
|
remove_proc_entry("svc",atm_proc_root);
|
if (arp)
|
if (arp)
|
remove_proc_entry("arp",atm_proc_root);
|
remove_proc_entry("arp",atm_proc_root);
|
if (lec)
|
if (lec)
|
remove_proc_entry("lec",atm_proc_root);
|
remove_proc_entry("lec",atm_proc_root);
|
if (vc)
|
if (vc)
|
remove_proc_entry("vc",atm_proc_root);
|
remove_proc_entry("vc",atm_proc_root);
|
remove_proc_entry("net/atm",NULL);
|
remove_proc_entry("net/atm",NULL);
|
}
|
}
|
|
|
int atm_proc_init(void)
|
int atm_proc_init(void)
|
{
|
{
|
atm_proc_root = proc_mkdir("net/atm",NULL);
|
atm_proc_root = proc_mkdir("net/atm",NULL);
|
if (!atm_proc_root)
|
if (!atm_proc_root)
|
return -ENOMEM;
|
return -ENOMEM;
|
CREATE_ENTRY(devices);
|
CREATE_ENTRY(devices);
|
CREATE_ENTRY(pvc);
|
CREATE_ENTRY(pvc);
|
CREATE_ENTRY(svc);
|
CREATE_ENTRY(svc);
|
CREATE_ENTRY(vc);
|
CREATE_ENTRY(vc);
|
#if defined(CONFIG_ATM_CLIP) || defined(CONFIG_ATM_CLIP_MODULE)
|
#if defined(CONFIG_ATM_CLIP) || defined(CONFIG_ATM_CLIP_MODULE)
|
CREATE_ENTRY(arp);
|
CREATE_ENTRY(arp);
|
#endif
|
#endif
|
#if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE)
|
#if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE)
|
CREATE_ENTRY(lec);
|
CREATE_ENTRY(lec);
|
#endif
|
#endif
|
return 0;
|
return 0;
|
|
|
cleanup:
|
cleanup:
|
atm_proc_cleanup();
|
atm_proc_cleanup();
|
return -ENOMEM;
|
return -ENOMEM;
|
}
|
}
|
|
|
void atm_proc_exit(void)
|
void atm_proc_exit(void)
|
{
|
{
|
atm_proc_cleanup();
|
atm_proc_cleanup();
|
}
|
}
|
|
|