/***************************************************************************** * wanproc.c WAN Router Module. /proc filesystem interface. * * This module is completely hardware-independent and provides * access to the router using Linux /proc filesystem. * * Author: Gideon Hack * Nenad Corbic * * Copyright: (c) 1995-2004 Sangoma Technologies Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * ============================================================================ * Aug 20, 2001 Alex Feldman Support SNMP. * May 25, 2001 Alex Feldman Added T1/E1 support (TE1). * May 23, 2001 Nenad Corbic Bug fix supplied by Akash Jain. If the user * copy fails free up allocated memory. * Jun 02, 1999 Gideon Hack Updates for Linux 2.2.X kernels. * Jun 29, 1997 Alan Cox Merged with 1.0.3 vendor code * Jan 29, 1997 Gene Kozin v1.0.1. Implemented /proc read routines * Jan 30, 1997 Alan Cox Hacked around for 2.1 * Dec 13, 1996 Gene Kozin Initial version (based on Sangoma's WANPIPE) *****************************************************************************/ #include "wanpipe_includes.h" #include "wanpipe_version.h" #include "wanpipe_defines.h" #include "wanpipe_debug.h" #include "wanpipe_common.h" #include "wanpipe.h" #include "sdladrv.h" #include "wanproc.h" #include "if_wanpipe_common.h" #if !defined(__WINDOWS__) #if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) # define STATIC # define CONFIG_PROC_FS #else # define STATIC static #endif #if defined(__LINUX__) # if defined(LINUX_2_1) || defined(LINUX_2_4) # ifndef proc_mkdir # define proc_mkdir(buf, usbdir) create_proc_entry(buf, S_IFDIR, usbdir) # endif # endif # if defined(LINUX_2_6) # define M_STOP_CNT(m) NULL # else # define M_STOP_CNT(m) &m->stop_cnt # endif #endif #define PROC_STATS_1_FORMAT "%25s: %10lu\n" #define PROC_STATS_2_FORMAT "%25s: %10lu %25s: %10lu\n" #define PROC_STATS_ALARM_FORMAT "%25s: %10s %25s: %10s\n" #define PROC_STATS_STR_FORMAT "%25s: %10s\n" /****** Defines and Macros **************************************************/ #ifndef wp_min #define wp_min(a,b) (((a)<(b))?(a):(b)) #endif #ifndef wp_max #define wp_max(a,b) (((a)>(b))?(a):(b)) #endif #define PROC_BUFSZ 4000 /* buffer size for printing proc info */ #define PROT_UNKNOWN "Unknown" #define PROT_DECODE(prot,cap) ((prot == WANCONFIG_FR) ? ((cap)?"FR":"fr") :\ (prot == WANCONFIG_MFR) ? ((cap)?"FR":"fr") : \ (prot == WANCONFIG_X25) ? ((cap)?"X25":"x25") : \ (prot == WANCONFIG_PPP) ? ((cap)?"PPP":"ppp") : \ (prot == WANCONFIG_CHDLC) ? ((cap)?"CHDLC":"chdlc") :\ (prot == WANCONFIG_ADSL) ? ((cap)?"ADSL":"adsl") :\ (prot == WANCONFIG_MPPP) ? ((cap)?"S51X":"s51x") : \ (prot == WANCONFIG_SDLC) ? ((cap)?"SDLC":"sdlc") : \ (prot == WANCONFIG_ATM) ? ((cap)?"ATM":"atm") : \ (prot == WANCONFIG_AFT) ? ((cap)?"AFT TE1":"aft te1") : \ (prot == WANCONFIG_AFT_T116) ? ((cap)?"AFT TE1":"aft te1") : \ (prot == WANCONFIG_AFT_SERIAL) ? ((cap)?"A-SERIAL":"aft serial") : \ (prot == WANCONFIG_AFT_ANALOG) ? ((cap)?"A-ANALOG":"aft analog") : \ (prot == WANCONFIG_AFT_GSM) ? ((cap)?"AFT GSM":"aft gsm") : \ (prot == WANCONFIG_AFT_ISDN_BRI) ? ((cap)?"AFT ISDN":"aft isdn") : \ (prot == WANCONFIG_AFT_56K) ? ((cap)?"AFT 56K":"aft 56k") : \ (prot == WANCONFIG_AFT_TE1) ? ((cap)?"AFT TE1":"aft te1") : \ (prot == WANCONFIG_AFT_TE3) ? ((cap)?"AFT TE3":"aft te3") : \ PROT_UNKNOWN ) #define CARD_DECODE(wandev) ((wandev->card_type == WANOPT_ADSL) ? "ADSL" : \ (wandev->card_type == WANOPT_S50X) ? "S508" : \ (wandev->card_type == WANOPT_AFT) ? "AFT TE1" : \ (wandev->card_type == WANOPT_AFT_101) ? "A101" : \ (wandev->card_type == WANOPT_AFT_102) ? "A102" : \ (wandev->card_type == WANOPT_AFT_104) ? "A104" : \ (wandev->card_type == WANOPT_AFT_108) ? "A108" : \ (wandev->card_type == WANOPT_AFT_300) ? "A301" : \ (wandev->card_type == WANOPT_AFT_300) ? "A301" : \ (wandev->card_type == WANOPT_AFT_ANALOG) ? "A200/A400" : \ (wandev->card_type == WANOPT_AFT_ISDN) ? "A500" : \ (wandev->card_type == WANOPT_AFT_SERIAL) ? "A14X" : \ (wandev->fe_iface.get_fe_media_string) ? \ wandev->fe_iface.get_fe_media_string() : "S514") /****** Data Types **********************************************************/ #if defined(__LINUX__) typedef struct wan_stat_entry { struct wan_stat_entry *next; char *description; /* description string */ void *data; /* -> data */ unsigned data_type; /* data type */ } wan_stat_entry_t; typedef struct wan_proc_entry { struct proc_dir_entry *protocol_entry; int count; } wan_proc_entry_t; #endif /****** Function Prototypes *************************************************/ extern wan_spinlock_t wan_devlist_lock; extern struct wan_devlist_ wan_devlist; #if defined(CONFIG_PROC_FS) #define CONF_PCI_FRM "%-12s| %-13s| %-9s| %-4u| %-8u| %-5u| %-4s| %-10u|\n" #define CONF_ISA_FRM "%-12s| %-13s| %-9s| %-4u| 0x%-6X| %-5u| %-4s| %-10u|\n" #define MAP_FRM "%-12s| %-50s\n" #define INTERFACES_FRM "%-15s| %-12s| %-6u| %-18s|\n" #define PROC_FR_FRM "%-30s\n" #define PROC_FR_CFG_FRM "%-15s| %-12s| %-5u|\n" #define PROC_FR_STAT_FRM "%-15s| %-12s| %-14s|\n" #ifdef CONFIG_PRODUCT_WANPIPE_ANNEXG #define STAT_FRM "%-12s| %-9s| %-8s| %-14s| %-3u | %-3u | %-3u | %-3u | %-3u | %-3u | %-3u | %-3u | %-3u | %-3u |\n" #else #define STAT_FRM "%-12s| %-9s| %-8s| %-14s|\n" #endif /* NEW_PROC */ /* Strings */ static char conf_hdr[] = "Device name | Protocol Map | Adapter | IRQ | Slot/IO " "| If's | CLK | Baud rate |\n"; #if defined(__LINUX__) static char map_hdr[] = "Device name | Protocol Map \n"; #endif #ifdef CONFIG_PRODUCT_WANPIPE_ANNEXG static char stat_hdr[] = "Device name | Protocol | Station | Status | Wanpipe | Lapb | X25 Link | X25 Svc | Dsp |\n"; #else static char stat_hdr[] = "Device name | Protocol | Station | Status |\n"; #endif static char interfaces_hdr[] = "Interface name | Device name | Media | Operational State |\n"; #if defined(__LINUX__) /* Proc filesystem interface */ #ifndef LINUX_2_6 static int router_proc_perms(struct inode *, int); static ssize_t router_proc_read(struct file*, char*, size_t,loff_t*); static ssize_t router_proc_write(struct file*, const char*, size_t,loff_t*); #endif /* Methods for preparing data for reading proc entries */ #if defined(LINUX_2_6) static int config_get_info(struct seq_file *m, void *v); static int status_get_info(struct seq_file *m, void *v); static int probe_get_info(struct seq_file *m, void *v); static int probe_get_info_legacy(struct seq_file *m, void *v); static int probe_get_info_verbose(struct seq_file *m, void *v); static int probe_get_info_dump(struct seq_file *m, void *v); static int wandev_get_info(struct seq_file *m, void *v); static int map_get_info(struct seq_file *m, void *v); static int interfaces_get_info(struct seq_file *m, void *v); static int get_dev_config_info(struct seq_file *m, void *v); static int get_dev_status_info(struct seq_file *m, void *v); static int wandev_mapdir_get_info(struct seq_file *m, void *v); #elif defined(LINUX_2_4) static int config_get_info(char* buf, char** start, off_t offs, int len); static int status_get_info(char* buf, char** start, off_t offs, int len); static int probe_get_info(char* buf, char** start, off_t offs, int len); static int probe_get_info_legacy(char* buf, char** start, off_t offs, int len); static int probe_get_info_verbose(char* buf, char** start, off_t offs, int len); static int probe_get_info_dump(char* buf, char** start, off_t offs, int len); static int wandev_get_info(char* buf, char** start, off_t offs, int len); static int map_get_info(char* buf, char** start, off_t offs, int len); static int interfaces_get_info(char* buf, char** start, off_t offs, int len); static int get_dev_config_info(char* buf, char** start, off_t offs, int len); static int get_dev_status_info(char* buf, char** start, off_t offs, int len); static int wandev_mapdir_get_info(char* buf, char** start, off_t offs, int len); #else static int config_get_info(char* buf, char** start, off_t offs, int len, int dummy); static int status_get_info(char* buf, char** start, off_t offs, int len, int dummy); static int probe_get_info(char* buf, char** start, off_t offs, int len, int dummy); static int probe_get_info_legacy(char* buf, char** start, off_t offs, int len, int dummy); static int probe_get_info_verbose(char* buf, char** start, off_t offs, int len, int dummy); static int probe_get_info_dump(char* buf, char** start, off_t offs, int len, int dummy); static int wandev_get_info(char* buf, char** start, off_t offs, int len, int dummy); static int map_get_info(char* buf, char** start, off_t offs, int len, int dummy); static int interfaces_get_info(char* buf, char** start, off_t offs, int len, int dummy); static int get_dev_config_info(char* buf, char** start, off_t offs, int len, int dummy); static int get_dev_status_info(char* buf, char** start, off_t offs, int len, int dummy); #endif /* Miscellaneous */ /* * Structures for interfacing with the /proc filesystem. * Router creates its own directory /proc/net/wanrouter with the folowing * entries: * config device configuration * status global device statistics * entry for each WAN device */ /* * Generic /proc/net/wanrouter/ file and inode operations */ struct proc_dir_entry *proc_router; static struct proc_dir_entry *map_dir; #ifdef LINUX_2_6 static int config_open(struct inode *inode, struct file *file) { return single_open(file, config_get_info, WP_PDE_DATA(inode)); } static int status_open(struct inode *inode, struct file *file) { return single_open(file, status_get_info, WP_PDE_DATA(inode)); } static struct file_operations config_fops = { .owner = THIS_MODULE, .open = config_open, .read = seq_read, .llseek = seq_lseek, .release = single_release, }; static struct file_operations status_fops = { .owner = THIS_MODULE, .open = status_open, .read = seq_read, .llseek = seq_lseek, .release = single_release, }; static int wandev_open(struct inode *inode, struct file *file) { return single_open(file, wandev_get_info, WP_PDE_DATA(inode)); } static struct file_operations wandev_fops = { .owner = THIS_MODULE, .open = wandev_open, .read = seq_read, .llseek = seq_lseek, .release = single_release, .WAN_IOCTL = wanrouter_ioctl, }; static int wp_hwprobe_open(struct inode *inode, struct file *file) { return single_open(file, probe_get_info, WP_PDE_DATA(inode)); } static struct file_operations wp_hwprobe_fops = { .owner = THIS_MODULE, .open = wp_hwprobe_open, .read = seq_read, .llseek = seq_lseek, .release = single_release, }; static int wp_hwprobe_legacy_open(struct inode *inode, struct file *file) { return single_open(file, probe_get_info_legacy, WP_PDE_DATA(inode)); } static struct file_operations wp_hwprobe_legacy_fops = { .owner = THIS_MODULE, .open = wp_hwprobe_legacy_open, .read = seq_read, .llseek = seq_lseek, .release = single_release, }; static int wp_hwprobe_verbose_open(struct inode *inode, struct file *file) { return single_open(file, probe_get_info_verbose, WP_PDE_DATA(inode)); } static struct file_operations wp_hwprobe_verbose_fops = { .owner = THIS_MODULE, .open = wp_hwprobe_verbose_open, .read = seq_read, .llseek = seq_lseek, .release = single_release, }; static int wp_hwprobe_dump_open(struct inode *inode, struct file *file) { return single_open(file, probe_get_info_dump, WP_PDE_DATA(inode)); } static struct file_operations wp_hwprobe_dump_fops = { .owner = THIS_MODULE, .open = wp_hwprobe_dump_open, .read = seq_read, .llseek = seq_lseek, .release = single_release, }; static int wp_map_open(struct inode *inode, struct file *file) { return single_open(file, map_get_info, WP_PDE_DATA(inode)); } static struct file_operations wp_map_fops = { .owner = THIS_MODULE, .open = wp_map_open, .read = seq_read, .llseek = seq_lseek, .release = single_release, }; static int wp_iface_open(struct inode *inode, struct file *file) { return single_open(file, interfaces_get_info, WP_PDE_DATA(inode)); } static struct file_operations wp_iface_fops = { .owner = THIS_MODULE, .open = wp_iface_open, .read = seq_read, .llseek = seq_lseek, .release = single_release, }; static int wandev_mapdir_open(struct inode *inode, struct file *file) { return single_open(file, wandev_mapdir_get_info, WP_PDE_DATA(inode)); } static struct file_operations wandev_mapdir_fops = { .owner = THIS_MODULE, .open = wandev_mapdir_open, .read = seq_read, .llseek = seq_lseek, .release = single_release, }; static int wp_get_dev_config_open(struct inode *inode, struct file *file) { return single_open(file, get_dev_config_info, WP_PDE_DATA(inode)); } static struct file_operations wp_get_dev_config_fops = { .owner = THIS_MODULE, .open = wp_get_dev_config_open, .read = seq_read, .llseek = seq_lseek, .release = single_release, }; static int wp_get_dev_status_open(struct inode *inode, struct file *file) { return single_open(file, get_dev_status_info, WP_PDE_DATA(inode)); } static struct file_operations wp_get_dev_status_fops = { .owner = THIS_MODULE, .open = wp_get_dev_status_open, .read = seq_read, .llseek = seq_lseek, .release = single_release, }; #if 0 static int wp_prot_dev_config_open(struct inode *inode, struct file *file) { return 0; //return single_open(file, get_dev_status_info, WP_PDE_DATA(inode)); } static struct file_operations wp_prot_dev_config_fops = { .owner = THIS_MODULE, .open = wp_prot_dev_config_open, .read = seq_read, .llseek = seq_lseek, .release = single_release, }; #endif #elif defined(LINUX_2_4) static struct file_operations router_fops = { read: router_proc_read, write: router_proc_write, }; static struct inode_operations router_inode = { permission: router_proc_perms, }; /* * /proc/net/wanrouter/ file operations */ static struct file_operations wandev_fops = { read: router_proc_read, WAN_IOCTL: wanrouter_ioctl, }; /* * /proc/net/wanrouter */ #else static struct file_operations router_fops = { NULL, /* lseek */ router_proc_read, /* read */ router_proc_write, /* write */ NULL, /* readdir */ NULL, /* select */ NULL, /* ioctl */ NULL, /* mmap */ NULL, /* no special open code */ NULL, /* flush */ NULL, /* no special release code */ NULL /* can't fsync */ }; static struct inode_operations router_inode = { &router_fops, NULL, /* create */ NULL, /* lookup */ NULL, /* link */ NULL, /* unlink */ NULL, /* symlink */ NULL, /* mkdir */ NULL, /* rmdir */ NULL, /* mknod */ NULL, /* rename */ NULL, /* follow link */ NULL, /* readlink */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ NULL, /* truncate */ router_proc_perms }; static struct file_operations wandev_fops = { NULL, /* lseek */ router_proc_read, /* read */ NULL, /* write */ NULL, /* readdir */ NULL, /* select */ wanrouter_ioctl, /* ioctl */ NULL, /* mmap */ NULL, /* no special open code */ NULL, /* flush */ NULL, /* no special release code */ NULL /* can't fsync */ }; static struct inode_operations wandev_inode = { &wandev_fops, NULL, /* create */ NULL, /* lookup */ NULL, /* link */ NULL, /* unlink */ NULL, /* symlink */ NULL, /* mkdir */ NULL, /* rmdir */ NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ NULL, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ NULL, /* truncate */ router_proc_perms }; #endif /* * /proc/net/wanrouter/ */ wan_proc_entry_t proc_router_fr; wan_proc_entry_t proc_router_chdlc; wan_proc_entry_t proc_router_ppp; wan_proc_entry_t proc_router_x25; #endif /* __LINUX__ */ /* * Interface functions */ /* * Prepare data for reading 'Config' entry. * Return length of data. */ #if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(LINUX_2_4) STATIC int config_get_info(char* buf, char** start, off_t offs, int len) #else #if defined(LINUX_2_6) static int config_get_info(struct seq_file *m, void *v) #elif defined(LINUX_2_4) static int config_get_info(char* buf, char** start, off_t offs, int len) #else static int config_get_info(char* buf, char** start, off_t offs, int len, int dummy) #endif #endif { wan_device_t* wandev = NULL; wan_smp_flag_t flags; PROC_ADD_DECL(m); PROC_ADD_INIT(m, buf, offs, len); PROC_ADD_LINE(m, "%s", conf_hdr); wan_spin_lock(&wan_devlist_lock,&flags); WAN_LIST_FOREACH(wandev, &wan_devlist, next){ /*for (wandev = router_devlist; wandev; wandev = wandev->next){*/ sdla_t* card = (sdla_t*)wandev->priv; u16 arg = 0; if (!wandev->state) continue; if (card && card->hw_iface.getcfg){ card->hw_iface.getcfg(card->hw, (wandev->card_type==WANOPT_S50X) ? SDLA_IOPORT : SDLA_SLOT, &arg); } if (wandev->state){ PROC_ADD_LINE(m , (wandev->card_type==WANOPT_S50X)?CONF_ISA_FRM:CONF_PCI_FRM, wandev->name, "N/A", /* FIXME */ SDLA_DECODE_CARDTYPE(wandev->card_type), wandev->irq, arg, wandev->ndev, (wandev->card_type==WANOPT_S51X || wandev->card_type==WANOPT_AFT_SERIAL) ? CLK_DECODE(wandev->clocking) : "N/A", wandev->bps); } } wan_spin_unlock(&wan_devlist_lock,&flags); PROC_ADD_RET(m); } /* * Prepare data for reading 'Status' entry. * Return length of data. */ #if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(LINUX_2_4) STATIC int status_get_info(char* buf, char** start, off_t offs, int len) #else #if defined(LINUX_2_6) static int status_get_info(struct seq_file *m, void *v) #elif defined(LINUX_2_4) static int status_get_info(char* buf, char** start, off_t offs, int len) #else static int status_get_info(char* buf, char** start, off_t offs, int len, int dummy) #endif #endif { struct wan_dev_le *devle; wan_device_t* wandev = NULL; wan_smp_flag_t flags; #ifdef CONFIG_PRODUCT_WANPIPE_ANNEXG netdevice_t *dev; wp_stack_stats_t wp_stats; #endif PROC_ADD_DECL(m); PROC_ADD_INIT(m, buf, offs, len); PROC_ADD_LINE(m, "%s", stat_hdr); devle=NULL; wan_spin_lock(&wan_devlist_lock,&flags); WAN_LIST_FOREACH(wandev, &wan_devlist, next){ if (!wandev->state) continue; #ifdef CONFIG_PRODUCT_WANPIPE_ANNEXG memset(&wp_stats,0,sizeof(wp_stack_stats_t)); if (wandev->get_active_inactive){ wan_spin_lock(&wandev->dev_head_lock,&flags); WAN_LIST_FOREACH(devle, &wandev->dev_head, dev_link){ dev = WAN_DEVLE2DEV(devle); if (!dev || !(dev->flags&IFF_UP) || !wan_netif_priv(dev)){ continue; } wandev->get_active_inactive(wandev,dev,&wp_stats); } wan_spin_unlock(&wandev->dev_head_lock,&flags); } PROC_ADD_LINE(m, STAT_FRM, wandev->name, PROT_DECODE(wandev->config_id,1), wandev->config_id == WANCONFIG_FR ? FR_STATION_DECODE(wandev->station) : wandev->config_id == WANCONFIG_MFR ? FR_STATION_DECODE(wandev->station) : wandev->config_id == WANCONFIG_ADSL ? ADSL_STATION_DECODE(wandev->station) : wandev->config_id == WANCONFIG_X25 ? X25_STATION_DECODE(wandev->station) : wandev->config_id == WANCONFIG_AFT ? "A1/2 TE1": wandev->config_id == WANCONFIG_AFT_TE1 ? "A104 TE1": wandev->config_id == WANCONFIG_AFT_TE3 ? "A300 TE3" : wandev->config_id == WANCONFIG_AFT_ANALOG ? "A200 RM" : ("N/A"), STATE_DECODE(wandev->state), wp_stats.fr_active,wp_stats.fr_inactive, wp_stats.lapb_active,wp_stats.lapb_inactive, wp_stats.x25_link_active,wp_stats.x25_link_inactive, wp_stats.x25_active,wp_stats.x25_inactive, wp_stats.dsp_active,wp_stats.dsp_inactive); #else PROC_ADD_LINE(m, STAT_FRM, wandev->name, PROT_DECODE(wandev->config_id,1), wandev->config_id == WANCONFIG_FR ? FR_STATION_DECODE(wandev->station) : wandev->config_id == WANCONFIG_MFR ? FR_STATION_DECODE(wandev->station) : wandev->config_id == WANCONFIG_ADSL ? ADSL_STATION_DECODE(wandev->station) : wandev->config_id == WANCONFIG_X25 ? X25_STATION_DECODE(wandev->station) : ("N/A"), STATE_DECODE(wandev->state)); #endif } wan_spin_unlock(&wan_devlist_lock,&flags); PROC_ADD_RET(m); } /* * Prepare data for reading 'Interfaces' entry. * Return length of data. */ #if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(LINUX_2_4) STATIC int interfaces_get_info(char* buf, char** start, off_t offs, int len) #else #if defined(LINUX_2_6) static int interfaces_get_info(struct seq_file *m, void *v) #elif defined(LINUX_2_4) static int interfaces_get_info(char* buf, char** start, off_t offs, int len) #else static int interfaces_get_info(char* buf, char** start, off_t offs, int len, int dummy) #endif #endif { struct wan_dev_le *devle; wan_device_t* wandev = NULL; netdevice_t* dev=NULL; wan_smp_flag_t flags; PROC_ADD_DECL(m); PROC_ADD_INIT(m, buf, offs, len); PROC_ADD_LINE(m, "%s", interfaces_hdr); wan_spin_lock(&wan_devlist_lock,&flags); WAN_LIST_FOREACH(wandev, &wan_devlist, next){ wanpipe_common_t *dev_priv; if (!(m->count < (m->size - 80))) break; if (!wandev->state) continue; wan_spin_lock(&wandev->dev_head_lock,&flags); WAN_LIST_FOREACH(devle, &wandev->dev_head, dev_link){ dev = WAN_DEVLE2DEV(devle); if (!dev || !WAN_NETIF_UP(dev) || !wan_netif_priv(dev)){ continue; } dev_priv = wan_netif_priv(dev); PROC_ADD_LINE(m, INTERFACES_FRM, wan_netif_name(dev), wandev->name, dev_priv->lcn, dev_priv?STATE_DECODE(dev_priv->state):"N/A"); if (dev_priv->usedby == STACK){ wanpipe_lip_get_if_status(dev_priv,m); } } wan_spin_unlock(&wandev->dev_head_lock,&flags); } wan_spin_unlock(&wan_devlist_lock,&flags); PROC_ADD_RET(m); } #define SANGOMA_COUNT_MESSAGE "\nSangoma Card Count: " #if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(LINUX_2_4) STATIC int probe_get_info(char* buf, char** start, off_t offs, int len) #else #if defined(LINUX_2_6) static int probe_get_info(struct seq_file *m, void *v) #elif defined(LINUX_2_4) static int probe_get_info(char* buf, char** start, off_t offs, int len) #else static int probe_get_info(char* buf, char** start, off_t offs, int len, int dummy) #endif #endif { int i=0; sdla_hw_probe_t* hw_probe; sdla_hw_type_cnt_t *hw_cnt; PROC_ADD_DECL(m); PROC_ADD_INIT(m, buf, offs, len); PROC_ADD_LINE(m, "-------------------------------\n"); PROC_ADD_LINE(m, "| Wanpipe Hardware Probe Info |\n"); PROC_ADD_LINE(m, "-------------------------------\n"); hw_probe = (sdla_hw_probe_t *)sdla_get_hw_probe(); for (; hw_probe; hw_probe = WAN_LIST_NEXT(hw_probe, next)) { if (hw_probe->index) { if (hw_probe->index > i) { i=hw_probe->index; } PROC_ADD_LINE(m, "%-2d. %s\n", hw_probe->index, hw_probe->hw_info); } } hw_probe = (sdla_hw_probe_t *)sdla_get_hw_probe(); for (; hw_probe; hw_probe = WAN_LIST_NEXT(hw_probe, next)) { if (!hw_probe->index) { i++; PROC_ADD_LINE(m, "%-2d. %s\n", i, hw_probe->hw_info); } } hw_cnt=(sdla_hw_type_cnt_t*)sdla_get_hw_adptr_cnt(); PROC_ADD_LINE(m, SANGOMA_COUNT_MESSAGE); if (hw_cnt->s508_adapters){ PROC_ADD_LINE(m, "S508=%d ", hw_cnt->s508_adapters); } if (hw_cnt->s514x_adapters){ PROC_ADD_LINE(m, "S514X=%d ", hw_cnt->s514x_adapters); } if (hw_cnt->s518_adapters){ PROC_ADD_LINE(m, "S518=%d ", hw_cnt->s518_adapters); } if (hw_cnt->aft101_adapters){ PROC_ADD_LINE(m, "A101-2=%d ", hw_cnt->aft101_adapters); } if (hw_cnt->aft104_adapters){ PROC_ADD_LINE(m, "A104=%d ", hw_cnt->aft104_adapters); } if (hw_cnt->aft108_adapters){ PROC_ADD_LINE(m, "A108=%d ", hw_cnt->aft108_adapters); } if (hw_cnt->aft200_adapters){ PROC_ADD_LINE(m, "A200=%d ", hw_cnt->aft200_adapters); } if (hw_cnt->aft_56k_adapters){ PROC_ADD_LINE(m, "A056=%d ", hw_cnt->aft_56k_adapters); } if (hw_cnt->aft_isdn_adapters){ PROC_ADD_LINE(m, "A500=%d ", hw_cnt->aft_isdn_adapters); } if (hw_cnt->aft_b500_adapters){ PROC_ADD_LINE(m, "B500=%d ", hw_cnt->aft_b500_adapters); } if (hw_cnt->aft_a700_adapters){ PROC_ADD_LINE(m, "B700=%d ", hw_cnt->aft_a700_adapters); } if (hw_cnt->aft_serial_adapters){ PROC_ADD_LINE(m, "A14x=%d ", hw_cnt->aft_serial_adapters); } if (hw_cnt->aft300_adapters){ PROC_ADD_LINE(m, "A300=%d ", hw_cnt->aft300_adapters); } if (hw_cnt->usb_adapters){ PROC_ADD_LINE(m, "U100=%d ", hw_cnt->usb_adapters); } if (hw_cnt->aft_a600_adapters){ PROC_ADD_LINE(m, "B600=%d ", hw_cnt->aft_a600_adapters); } if (hw_cnt->aft_b601_adapters){ PROC_ADD_LINE(m, "B601=%d ", hw_cnt->aft_b601_adapters); } if (hw_cnt->aft_b610_adapters){ PROC_ADD_LINE(m, "B610=%d ", hw_cnt->aft_b610_adapters); } if (hw_cnt->aft_b800_adapters){ PROC_ADD_LINE(m, "B800=%d ", hw_cnt->aft_b800_adapters); } if (hw_cnt->aft_w400_adapters){ PROC_ADD_LINE(m, "W400=%d ", hw_cnt->aft_w400_adapters); } if (hw_cnt->aft116_adapters){ PROC_ADD_LINE(m, "A116=%d ", hw_cnt->aft116_adapters); } if (hw_cnt->aft_t116_adapters){ PROC_ADD_LINE(m, "T116=%d ", hw_cnt->aft_t116_adapters); } PROC_ADD_LINE(m, "\n"); PROC_ADD_RET(m); } #if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(LINUX_2_4) STATIC int probe_get_info_legacy(char* buf, char** start, off_t offs, int len) #else #if defined(LINUX_2_6) static int probe_get_info_legacy(struct seq_file *m, void *v) #elif defined(LINUX_2_4) static int probe_get_info_legacy(char* buf, char** start, off_t offs, int len) #else static int probe_get_info_legacy(char* buf, char** start, off_t offs, int len, int dummy) #endif #endif { int i=0; sdla_hw_probe_t* hw_probe; sdla_hw_type_cnt_t *hw_cnt; PROC_ADD_DECL(m); PROC_ADD_INIT(m, buf, offs, len); PROC_ADD_LINE(m, "----------------------------------------\n"); PROC_ADD_LINE(m, "| Wanpipe Hardware Probe Info (Legacy) |\n"); PROC_ADD_LINE(m, "----------------------------------------\n"); hw_probe = (sdla_hw_probe_t *)sdla_get_hw_probe(); for (; hw_probe; hw_probe = WAN_LIST_NEXT(hw_probe, next)) { i++; PROC_ADD_LINE(m, "%-2d. %s\n", i, hw_probe->hw_info); } hw_cnt=(sdla_hw_type_cnt_t*)sdla_get_hw_adptr_cnt(); PROC_ADD_LINE(m, "\nCard Cnt: S508=%d S514X=%d S518=%d A101-2=%d A104=%d A300=%d A200=%d A108=%d A056=%d\n A500=%d A14x=%d A600=%d B601=%d A116=%d\n", hw_cnt->s508_adapters, hw_cnt->s514x_adapters, hw_cnt->s518_adapters, hw_cnt->aft101_adapters, hw_cnt->aft104_adapters, hw_cnt->aft300_adapters, hw_cnt->aft200_adapters, hw_cnt->aft108_adapters, hw_cnt->aft_56k_adapters, hw_cnt->aft_isdn_adapters, hw_cnt->aft_serial_adapters, hw_cnt->aft_a600_adapters, hw_cnt->aft_b601_adapters, hw_cnt->aft116_adapters ); PROC_ADD_RET(m); } #if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(LINUX_2_4) STATIC int probe_get_info_verbose(char* buf, char** start, off_t offs, int len) #else # if defined(LINUX_2_6) static int probe_get_info_verbose(struct seq_file *m, void *v) # elif defined(LINUX_2_4) static int probe_get_info_verbose(char* buf, char** start, off_t offs, int len) # else static int probe_get_info_verbose(char* buf, char** start, off_t offs, int len, int dummy) # endif #endif { int i=0; sdla_hw_probe_t* hw_probe; sdla_hw_type_cnt_t *hw_cnt; PROC_ADD_DECL(m); PROC_ADD_INIT(m, buf, offs, len); PROC_ADD_LINE(m, "-----------------------------------------\n"); PROC_ADD_LINE(m, "| Wanpipe Hardware Probe Info (verbose) |\n"); PROC_ADD_LINE(m, "-----------------------------------------\n"); hw_probe = (sdla_hw_probe_t *)sdla_get_hw_probe(); for (; hw_probe; hw_probe = WAN_LIST_NEXT(hw_probe, next)) { if (hw_probe->index) { if (hw_probe->index > i) { i=hw_probe->index; } PROC_ADD_LINE(m, "%-2d. %s", hw_probe->index, hw_probe->hw_info); PROC_ADD_LINE(m, "%s\n", hw_probe->hw_info_verbose); } } hw_probe = (sdla_hw_probe_t *)sdla_get_hw_probe(); for (; hw_probe; hw_probe = WAN_LIST_NEXT(hw_probe, next)) { if (!hw_probe->index) { i++; PROC_ADD_LINE(m, "%-2d. %s", i, hw_probe->hw_info); PROC_ADD_LINE(m, "%s\n", hw_probe->hw_info_verbose); } } hw_cnt=(sdla_hw_type_cnt_t*)sdla_get_hw_adptr_cnt(); PROC_ADD_LINE(m, SANGOMA_COUNT_MESSAGE); if (hw_cnt->s508_adapters){ PROC_ADD_LINE(m, "S508=%d ", hw_cnt->s508_adapters); } if (hw_cnt->s514x_adapters){ PROC_ADD_LINE(m, "S514X=%d ", hw_cnt->s514x_adapters); } if (hw_cnt->s518_adapters){ PROC_ADD_LINE(m, "S518=%d ", hw_cnt->s518_adapters); } if (hw_cnt->aft101_adapters){ PROC_ADD_LINE(m, "A101-2=%d ", hw_cnt->aft101_adapters); } if (hw_cnt->aft104_adapters){ PROC_ADD_LINE(m, "A104=%d ", hw_cnt->aft104_adapters); } if (hw_cnt->aft108_adapters){ PROC_ADD_LINE(m, "A108=%d ", hw_cnt->aft108_adapters); } if (hw_cnt->aft200_adapters){ PROC_ADD_LINE(m, "A200=%d ", hw_cnt->aft200_adapters); } if (hw_cnt->aft_56k_adapters){ PROC_ADD_LINE(m, "A056=%d ", hw_cnt->aft_56k_adapters); } if (hw_cnt->aft_isdn_adapters){ PROC_ADD_LINE(m, "A500=%d ", hw_cnt->aft_isdn_adapters); } if (hw_cnt->aft_a700_adapters){ PROC_ADD_LINE(m, "B700=%d ", hw_cnt->aft_a700_adapters); } if (hw_cnt->aft_serial_adapters){ PROC_ADD_LINE(m, "A14x=%d ", hw_cnt->aft_serial_adapters); } if (hw_cnt->aft300_adapters){ PROC_ADD_LINE(m, "A300=%d ", hw_cnt->aft300_adapters); } if (hw_cnt->usb_adapters){ PROC_ADD_LINE(m, "U100=%d ", hw_cnt->usb_adapters); } if (hw_cnt->aft_a600_adapters){ PROC_ADD_LINE(m, "B600=%d ", hw_cnt->aft_a600_adapters); } if (hw_cnt->aft_b601_adapters){ PROC_ADD_LINE(m, "B601=%d ", hw_cnt->aft_b601_adapters); } if (hw_cnt->aft_b800_adapters){ PROC_ADD_LINE(m, "B800=%d ", hw_cnt->aft_b800_adapters); } if (hw_cnt->aft_w400_adapters){ PROC_ADD_LINE(m, "W400=%d ", hw_cnt->aft_w400_adapters); } if (hw_cnt->aft116_adapters){ PROC_ADD_LINE(m, "A116=%d ", hw_cnt->aft116_adapters); } if (hw_cnt->aft_t116_adapters){ PROC_ADD_LINE(m, "T116=%d ", hw_cnt->aft_t116_adapters); } PROC_ADD_LINE(m, "\n"); PROC_ADD_RET(m); } #if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(LINUX_2_4) STATIC int probe_get_info_dump(char* buf, char** start, off_t offs, int len) #else # if defined(LINUX_2_6) static int probe_get_info_dump(struct seq_file *m, void *v) # elif defined(LINUX_2_4) static int probe_get_info_dump(char* buf, char** start, off_t offs, int len) # else static int probe_get_info_dump(char* buf, char** start, off_t offs, int len, int dummy) # endif #endif { int i=0; sdla_hw_probe_t* hw_probe; sdla_hw_type_cnt_t *hw_cnt; PROC_ADD_DECL(m); PROC_ADD_INIT(m, buf, offs, len); hw_probe = (sdla_hw_probe_t *)sdla_get_hw_probe(); for (; hw_probe; hw_probe = WAN_LIST_NEXT(hw_probe, next)) { if (hw_probe->index) { if (hw_probe->index > i) { i=hw_probe->index; } PROC_ADD_LINE(m, "|%d%s\n", hw_probe->index, hw_probe->hw_info_dump); } } hw_probe = (sdla_hw_probe_t *)sdla_get_hw_probe(); for (; hw_probe; hw_probe = WAN_LIST_NEXT(hw_probe, next)) { if (!hw_probe->index) { i++; PROC_ADD_LINE(m, "|%d%s\n", i, hw_probe->hw_info_dump); } } hw_cnt=(sdla_hw_type_cnt_t*)sdla_get_hw_adptr_cnt(); PROC_ADD_LINE(m, "|Card Cnt|S508=%d|S514X=%d|S518=%d|A101-2=%d|A104=%d|A300=%d|A200=%d|A108=%d|A056=%d|A500=%d|B700=%d|B600=%d|B601=%d|A14x=%d|A116=%d|T116=%d|W400=%d|\n", hw_cnt->s508_adapters, hw_cnt->s514x_adapters, hw_cnt->s518_adapters, hw_cnt->aft101_adapters, hw_cnt->aft104_adapters, hw_cnt->aft300_adapters, hw_cnt->aft200_adapters, hw_cnt->aft108_adapters, hw_cnt->aft_56k_adapters, hw_cnt->aft_isdn_adapters, hw_cnt->aft_a700_adapters, hw_cnt->aft_a600_adapters, hw_cnt->aft_b601_adapters, hw_cnt->aft_serial_adapters, hw_cnt->aft116_adapters, hw_cnt->aft_t116_adapters, hw_cnt->aft_w400_adapters); PROC_ADD_RET(m); } /* * Prepare data for reading entry. * Return length of data. * * On entry, the 'start' argument will contain a pointer to WAN device * data space. */ #if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(LINUX_2_4) STATIC int wandev_get_info(char* buf, char** start, off_t offs, int len) #else #if defined(LINUX_2_6) static int wandev_get_info(struct seq_file *m, void *v) #elif defined(LINUX_2_4) static int wandev_get_info(char* buf, char** start, off_t offs, int len) #else static int wandev_get_info(char* buf, char** start, off_t offs, int len, int dummy) #endif #endif { wan_device_t* wandev = PROC_GET_DATA(); int rslt = 0; PROC_ADD_DECL(m); if ((wandev == NULL) || (wandev->magic != ROUTER_MAGIC)) return 0; PROC_ADD_INIT(m, buf, offs, len); if (!wandev->state){ PROC_ADD_LINE(m, "device is not configured!\n"); goto wandev_get_info_end; } /* Update device statistics */ if (wandev->update && !m->from){ rslt = wandev->update(wandev); if(rslt) { switch (rslt) { case -EAGAIN: PROC_ADD_LINE(m, "Device is busy!\n"); break; default: PROC_ADD_LINE(m, "Device is not configured!\n"); break; } goto wandev_get_info_end; } } PROC_ADD_LINE(m, PROC_STATS_2_FORMAT, "total rx packets", wandev->stats.rx_packets, "total tx packets", wandev->stats.tx_packets); PROC_ADD_LINE(m, PROC_STATS_2_FORMAT, "total rx bytes", wandev->stats.rx_bytes, "total tx bytes", wandev->stats.tx_bytes); PROC_ADD_LINE(m, PROC_STATS_2_FORMAT, "bad rx packets", wandev->stats.rx_errors, "packet tx problems", wandev->stats.tx_errors); PROC_ADD_LINE(m, PROC_STATS_2_FORMAT, "rx frames dropped", wandev->stats.rx_dropped, "tx frames dropped", wandev->stats.tx_dropped); PROC_ADD_LINE(m, PROC_STATS_2_FORMAT, "multicast rx packets", wandev->stats.multicast, "tx collisions", wandev->stats.collisions); PROC_ADD_LINE(m, PROC_STATS_2_FORMAT, "rx length errors", wandev->stats.rx_length_errors, "rx overrun errors", wandev->stats.rx_over_errors); PROC_ADD_LINE(m, PROC_STATS_2_FORMAT, "CRC errors", wandev->stats.rx_crc_errors, "abort frames", wandev->stats.rx_frame_errors); PROC_ADD_LINE(m, PROC_STATS_2_FORMAT, "rx fifo overrun", wandev->stats.rx_fifo_errors, "rx missed packet", wandev->stats.rx_missed_errors); PROC_ADD_LINE(m, PROC_STATS_1_FORMAT, "aborted tx frames", wandev->stats.tx_aborted_errors); /* Update Front-End information (alarms, performance monitor counters */ if (wandev->get_info){ m->count = wandev->get_info( wandev->priv, m, M_STOP_CNT(m)); } wandev_get_info_end: PROC_ADD_RET(m); } #if defined(__LINUX__) #ifdef LINUX_2_6 #define FPTR(st) (&st) #else #define FPTR(st) NULL #endif static inline struct proc_dir_entry *wp_proc_create(const char *name, umode_t mode, struct proc_dir_entry *parent, struct file_operations *proc_fops) { struct proc_dir_entry *p = NULL; #ifdef LINUX_3_0 p = proc_create(name, mode, parent, proc_fops); #elif defined(LINUX_2_6) p = create_proc_entry(name, mode, parent); if (!p) { return NULL; } p->proc_fops = proc_fops; #elif defined(LINUX_2_4) p = create_proc_entry(name, mode, parent); if (!p) { return NULL; } /* In 2.4 we always default to router_fops and router_inode */ if (!proc_fops) { p->proc_fops = &router_fops; } p->proc_iops = &router_inode; #else p = create_proc_entry(name, mode, parent); if (!p) { return NULL; } /* In Pre-2.4 we always default to router_inode */ p->ops = &router_inode; p->nlink = 1; #endif return p; } static inline struct proc_dir_entry *wp_proc_create_data(const char *name, umode_t mode, struct proc_dir_entry *parent, struct file_operations *proc_fops, void *data) { struct proc_dir_entry *p = NULL; #ifdef LINUX_3_0 p = proc_create_data(name, mode, parent, proc_fops, data); #else p = wp_proc_create(name, mode, parent, proc_fops); if (p) { p->data = data; } #endif return p; } /* * Initialize router proc interface. */ int wanrouter_proc_init (void) { struct proc_dir_entry *p; proc_router = proc_mkdir(ROUTER_NAME, wan_init_net(proc_net)); if (!proc_router) goto fail; p = wp_proc_create("config",S_IRUGO,proc_router,FPTR(config_fops)); if (!p) goto fail_config; #ifndef LINUX_2_6 p->get_info = config_get_info; #endif p = wp_proc_create("status",S_IRUGO,proc_router,FPTR(status_fops)); if (!p) goto fail_stat; #ifndef LINUX_2_6 p->get_info = status_get_info; #endif p = wp_proc_create("hwprobe",0,proc_router,FPTR(wp_hwprobe_fops)); if (!p) goto fail_probe; #ifndef LINUX_2_6 p->get_info = probe_get_info; #endif p = wp_proc_create("hwprobe_legacy",0,proc_router,FPTR(wp_hwprobe_legacy_fops)); if (!p) goto fail_probe_legacy; #ifndef LINUX_2_6 p->get_info = probe_get_info_legacy; #endif p = wp_proc_create("hwprobe_verbose",0,proc_router,FPTR(wp_hwprobe_verbose_fops)); if (!p) goto fail_probe_verbose; #ifndef LINUX_2_6 p->get_info = probe_get_info_verbose; #endif p = wp_proc_create("hwprobe_dump",0,proc_router,FPTR(wp_hwprobe_dump_fops)); if (!p) goto fail_probe_dump; #ifndef LINUX_2_6 p->get_info = probe_get_info_dump; #endif p = wp_proc_create("map",0,proc_router,FPTR(wp_map_fops)); if (!p) goto fail_map; #ifndef LINUX_2_6 p->get_info = map_get_info; #endif p = wp_proc_create("interfaces",0,proc_router,FPTR(wp_iface_fops)); if (!p) goto fail_interfaces; #ifndef LINUX_2_6 p->get_info = interfaces_get_info; #endif map_dir = proc_mkdir("dev_map", proc_router); if (!map_dir) goto fail_dev_map; /* Initialize protocol proc fs. */ proc_router_chdlc.count = 0; proc_router_chdlc.protocol_entry = NULL; proc_router_fr.count = 0; proc_router_fr.protocol_entry = NULL; proc_router_ppp.count = 0; proc_router_ppp.protocol_entry = NULL; proc_router_x25.count = 0; proc_router_x25.protocol_entry = NULL; return 0; fail_dev_map: remove_proc_entry("interfaces", proc_router); fail_interfaces: remove_proc_entry("map", proc_router); fail_map: remove_proc_entry("hwprobe_dump", proc_router); fail_probe_dump: remove_proc_entry("hwprobe_verbose", proc_router); fail_probe_verbose: remove_proc_entry("hwprobe_legacy", proc_router); fail_probe_legacy: remove_proc_entry("hwprobe", proc_router); fail_probe: remove_proc_entry("status", proc_router); fail_stat: remove_proc_entry("config", proc_router); fail_config: remove_proc_entry(ROUTER_NAME, wan_init_net(proc_net)); fail: return -ENOMEM; } /* * Clean up router proc interface. */ void wanrouter_proc_cleanup (void) { remove_proc_entry("config", proc_router); remove_proc_entry("status", proc_router); remove_proc_entry("hwprobe", proc_router); remove_proc_entry("hwprobe_legacy", proc_router); remove_proc_entry("hwprobe_verbose", proc_router); remove_proc_entry("hwprobe_dump", proc_router); remove_proc_entry("map", proc_router); remove_proc_entry("interfaces", proc_router); remove_proc_entry("dev_map",proc_router); remove_proc_entry(ROUTER_NAME,wan_init_net(proc_net)); } /* * Add directory entry for WAN device. */ int wanrouter_proc_add (wan_device_t* wandev) { int err=0; struct proc_dir_entry *p; wan_spin_lock_init(&wandev->get_map_lock, "wan_proc_lock"); if (wandev->magic != ROUTER_MAGIC) return -EINVAL; wandev->dent = wp_proc_create_data(wandev->name, S_IRUGO, proc_router, FPTR(wandev_fops), wandev); if (!wandev->dent) return -ENOMEM; #if !defined(LINUX_2_6) wandev->dent->get_info = wandev_get_info; #endif p = wp_proc_create_data(wandev->name, 0, map_dir, FPTR(wandev_mapdir_fops), wandev); if (!p){ remove_proc_entry(wandev->name, proc_router); wandev->dent=NULL; return -ENOMEM; } #if !defined(LINUX_2_6) #if defined(LINUX_2_4) p->proc_fops = &wandev_fops; p->proc_iops = &router_inode; p->get_info = wandev_mapdir_get_info; #else p->ops = &wandev_inode; p->get_info = wandev_mapdir_get_info; #endif #endif return err; } /* * Delete directory entry for WAN device. */ int wanrouter_proc_delete(wan_device_t* wandev) { if (wandev->magic != ROUTER_MAGIC) return -EINVAL; remove_proc_entry(wandev->name, proc_router); remove_proc_entry(wandev->name, map_dir); return 0; } /* * Add directory entry for Protocol. */ int wanrouter_proc_add_protocol(wan_device_t* wandev) { struct proc_dir_entry* p = NULL; //struct proc_dir_entry** proc_protocol; wan_proc_entry_t* proc_protocol; if (wandev->magic != ROUTER_MAGIC) return -EINVAL; switch(wandev->config_id){ case WANCONFIG_FR: case WANCONFIG_MFR: proc_protocol = &proc_router_fr; break; case WANCONFIG_CHDLC: proc_protocol = &proc_router_chdlc; break; case WANCONFIG_PPP: proc_protocol = &proc_router_ppp; break; case WANCONFIG_X25: proc_protocol = &proc_router_x25; break; default: proc_protocol = NULL; return 0; } if (proc_protocol->protocol_entry == NULL){ proc_protocol->count=0; /* Create /proc/net/wanrouter/ directory */ proc_protocol->protocol_entry = proc_mkdir(PROT_DECODE(wandev->config_id,0), proc_router); if (!proc_protocol->protocol_entry) goto fail; /* Create /proc/net/wanrouter//config directory */ p = wp_proc_create_data("config",0,proc_protocol->protocol_entry,FPTR(wp_get_dev_config_fops),((void *)(long)wandev->config_id)); if (!p) goto fail_config; #if !defined(LINUX_2_6) p->get_info = get_dev_config_info; #endif /* Create /proc/net/wanrouter//status directory */ p = wp_proc_create_data("status",0,proc_protocol->protocol_entry,FPTR(wp_get_dev_status_fops),((void *)(long)wandev->config_id)); if (!p) goto fail_stat; #if !defined(LINUX_2_6) p->get_info = get_dev_status_info; #endif } /* Create /proc/net/wanrouter// directory */ wandev->link = proc_mkdir(wandev->name, proc_protocol->protocol_entry); if (!wandev->link) goto fail_link; /* Create /proc/net/wanrouter//config directory */ p = wp_proc_create_data("config",0,wandev->link,NULL,wandev); if (!p) goto fail_link_config; #if !defined(LINUX_2_6) p->get_info = wandev->get_dev_config_info; p->write_proc = wandev->set_dev_config; #endif proc_protocol->count ++; return 0; fail_link_config: remove_proc_entry(wandev->name, proc_protocol->protocol_entry); fail_link: if (proc_protocol->count){ /* Do not remove /proc/net/wanrouter/... because * another device is still using this entry. */ return -ENOMEM; } remove_proc_entry("status", proc_protocol->protocol_entry); return -ENOMEM; fail_stat: remove_proc_entry("config", proc_protocol->protocol_entry); fail_config: remove_proc_entry(PROT_DECODE(wandev->config_id,0), proc_router); proc_protocol->protocol_entry = NULL; fail: return -ENOMEM; } /* * Delete directory entry for Protocol. */ int wanrouter_proc_delete_protocol(wan_device_t* wandev) { wan_proc_entry_t* proc_protocol = NULL; if (wandev->magic != ROUTER_MAGIC) return -EINVAL; switch(wandev->config_id){ case WANCONFIG_FR: case WANCONFIG_MFR: proc_protocol = &proc_router_fr; break; case WANCONFIG_CHDLC: proc_protocol = &proc_router_chdlc; break; case WANCONFIG_PPP: proc_protocol = &proc_router_ppp; break; case WANCONFIG_X25: proc_protocol = &proc_router_x25; break; default: proc_protocol = NULL; return 0; break; } remove_proc_entry("config", wandev->link); remove_proc_entry(wandev->name, proc_protocol->protocol_entry); proc_protocol->count --; if (!proc_protocol->count){ remove_proc_entry("config", proc_protocol->protocol_entry); remove_proc_entry("status", proc_protocol->protocol_entry); remove_proc_entry(PROT_DECODE(wandev->config_id,0), proc_router); proc_protocol->protocol_entry = NULL; } return 0; } /* * Add directory entry for interface. */ int wanrouter_proc_add_interface(wan_device_t* wandev, struct proc_dir_entry** dent, char* if_name, void* priv) { #if 0 if (wandev->magic != ROUTER_MAGIC) return -EINVAL; if (wandev->link == NULL || wandev->get_if_info == NULL) return -ENODEV; *dent = create_proc_entry(if_name, 0, wandev->link); if (!*dent) return -ENOMEM; #ifdef LINUX_2_4 (*dent)->proc_fops = &router_fops; (*dent)->proc_iops = &router_inode; #else (*dent)->ops = &router_inode; (*dent)->nlink = 1; #endif (*dent)->get_info = wandev->get_if_info; (*dent)->write_proc = wandev->set_if_info; (*dent)->data = priv; #endif return 0; } /* * Delete directory entry for interface. */ int wanrouter_proc_delete_interface(wan_device_t* wandev, char* if_name) { #if 0 if (wandev->magic != ROUTER_MAGIC) return -EINVAL; if (wandev->link == NULL) return -ENODEV; remove_proc_entry(if_name, wandev->link); #endif return 0; } /****** Proc filesystem entry points ****************************************/ /* * Verify access rights. */ #ifndef LINUX_2_6 static int router_proc_perms (struct inode* inode, int op) { return 0; } /* * Read router proc directory entry. * This is universal routine for reading all entries in /proc/net/wanrouter * directory. Each directory entry contains a pointer to the 'method' for * preparing data for that entry. * o verify arguments * o allocate kernel buffer * o call get_info() to prepare data * o copy data to user space * o release kernel buffer * * Return: number of bytes copied to user space (0, if no data) * <0 error */ static ssize_t router_proc_read(struct file* file, char* buf, size_t count, loff_t *ppos) { struct inode *inode = file->f_dentry->d_inode; struct proc_dir_entry* dent; char* page; int len; if (count <= 0) return 0; #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18) dent = inode->i_private; #else dent = inode->u.generic_ip; #endif if ((dent == NULL) || (dent->get_info == NULL)) return 0; page = wan_malloc(count); if (page == NULL) return -ENOBUFS; #ifdef LINUX_2_4 len = dent->get_info(page, dent->data, file->f_pos, count); #else len = dent->get_info(page, dent->data, file->f_pos, count, 0); #endif if (len) { if(copy_to_user(buf, page, len)){ DEBUG_SUB_MEM(count); wan_free(page); return -EFAULT; } file->f_pos += len; } wan_free(page); return len; } /* * Write router proc directory entry. * This is universal routine for writing all entries in /proc/net/wanrouter * directory. Each directory entry contains a pointer to the 'method' for * preparing data for that entry. * o verify arguments * o allocate kernel buffer * o copy data from user space * o call write_info() * o release kernel buffer * * Return: number of bytes copied to user space (0, if no data) * <0 error */ static ssize_t router_proc_write (struct file *file, const char *buf, size_t count, loff_t *ppos) { struct inode* inode = file->f_dentry->d_inode; struct proc_dir_entry* dent = NULL; char* page = NULL; #ifdef WAN_DEBUG_MEM unsigned int ocount=count; #endif if (count <= 0) return 0; #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,18) dent = inode->i_private; #else dent = inode->u.generic_ip; #endif if ((dent == NULL) || (dent->write_proc == NULL)) return count; page = wan_malloc(count); if (page == NULL) return -ENOBUFS; if (copy_from_user(page, buf, count)){ DEBUG_SUB_MEM(count); wan_free(page); return -EINVAL; } page[count-1] = '\0'; /* Add supporting Write to proc fs */ count = dent->write_proc(file, page, count, dent->data); DEBUG_SUB_MEM(ocount); wan_free(page); return count; } #endif /* * Prepare data for reading 'MAP' entry. * Return length of data. */ #if defined(LINUX_2_6) static int map_get_info(struct seq_file *m, void *v) #elif defined(LINUX_2_4) static int map_get_info(char* buf, char** start, off_t offs, int len) #else static int map_get_info(char* buf, char** start, off_t offs, int len, int dummy) #endif { wan_device_t* wandev = NULL; struct wan_dev_le *devle; netdevice_t* dev=NULL; wan_smp_flag_t flags; PROC_ADD_DECL(m); PROC_ADD_INIT(m, buf, offs, len); PROC_ADD_LINE(m, "%s", map_hdr); wan_spin_lock(&wan_devlist_lock,&flags); WAN_LIST_FOREACH(wandev, &wan_devlist, next){ if (!wandev->state){ continue; } if (!wandev->get_map){ continue; } wan_spin_lock(&wandev->dev_head_lock,&flags); WAN_LIST_FOREACH(devle, &wandev->dev_head, dev_link){ dev = WAN_DEVLE2DEV(devle); if (!dev || !(dev->flags&IFF_UP) || !wan_netif_priv(dev)){ continue; } m->count = wandev->get_map(wandev, dev, m, M_STOP_CNT(m)); } wan_spin_unlock(&wandev->dev_head_lock,&flags); } wan_spin_unlock(&wan_devlist_lock,&flags); PROC_ADD_RET(m); } /* * Prepare data for reading FR 'Config' entry. * Return length of data. */ #if defined(LINUX_2_6) static int get_dev_config_info(struct seq_file *m, void *v) #elif defined(LINUX_2_4) static int get_dev_config_info(char* buf, char** start, off_t offs, int len) #else static int get_dev_config_info(char* buf, char** start, off_t offs, int len,int dummy) #endif { wan_device_t* wandev = NULL; netdevice_t* dev = NULL; wan_smp_flag_t flags; struct wan_dev_le *devle; PROC_ADD_DECL(m); PROC_ADD_INIT(m, buf, offs, len); wan_spin_lock(&wan_devlist_lock,&flags); WAN_LIST_FOREACH(wandev, &wan_devlist, next){ if (!(m->count < (PROC_BUFSZ - 80))) break; if (!wandev->get_config_info) continue; #ifndef LINUX_2_6 if ((wandev->config_id != (unsigned)start) || !wandev->state) continue; #else if (!wandev->state) continue; #endif wan_spin_lock(&wandev->dev_head_lock,&flags); WAN_LIST_FOREACH(devle, &wandev->dev_head, dev_link){ dev = WAN_DEVLE2DEV(devle); if (!dev || !(dev->flags&IFF_UP) || !wan_netif_priv(dev)){ continue; } m->count = wandev->get_config_info(wan_netif_priv(dev), m, M_STOP_CNT(m)); } wan_spin_unlock(&wandev->dev_head_lock,&flags); } wan_spin_unlock(&wan_devlist_lock,&flags); PROC_ADD_RET(m); } /* * Prepare data for reading FR 'Status' entry. * Return length of data. */ #if defined(LINUX_2_6) static int get_dev_status_info(struct seq_file *m, void *v) #elif defined(LINUX_2_4) static int get_dev_status_info(char* buf, char** start, off_t offs, int len) #else static int get_dev_status_info(char* buf, char** start, off_t offs, int len, int dummy) #endif { wan_device_t* wandev = NULL; struct wan_dev_le *devle; netdevice_t* dev = NULL; int cnt = 0; wan_smp_flag_t flags; PROC_ADD_DECL(m); PROC_ADD_INIT(m, buf, offs, len); wan_spin_lock(&wan_devlist_lock,&flags); WAN_LIST_FOREACH(wandev, &wan_devlist, next){ if (!(cnt < (PROC_BUFSZ - 80))) break; if (!wandev->get_status_info) continue; #ifndef LINUX_2_6 if ((wandev->config_id != (unsigned)start) || !wandev->state) continue; #else if (!wandev->state) continue; #endif wan_spin_lock(&wandev->dev_head_lock,&flags); WAN_LIST_FOREACH(devle, &wandev->dev_head, dev_link){ dev = WAN_DEVLE2DEV(devle); if (!dev || !(dev->flags&IFF_UP) || !wan_netif_priv(dev)){ continue; } m->count = wandev->get_status_info(wan_netif_priv(dev), m, M_STOP_CNT(m)); } wan_spin_unlock(&wandev->dev_head_lock,&flags); } wan_spin_unlock(&wan_devlist_lock,&flags); PROC_ADD_RET(m); } #if defined(LINUX_2_6) static int wandev_mapdir_get_info(struct seq_file *m, void *v) #elif defined(LINUX_2_4) static int wandev_mapdir_get_info(char* buf, char** start, off_t offs, int len) #else static int wandev_mapdir_get_info(char* buf, char** start, off_t offs, int len, int dummy) #endif { wan_device_t* wandev = PROC_GET_DATA(); struct wan_dev_le *devle; netdevice_t* dev = NULL; wan_smp_flag_t flags; PROC_ADD_DECL(m); if (!wandev){ return -ENODEV; } PROC_ADD_INIT(m, buf, offs, len); PROC_ADD_LINE(m, "%s", map_hdr); if (!wandev->state){ goto wandev_mapdir_get_info_exit; } if (!wandev->get_map){ goto wandev_mapdir_get_info_exit; } wan_spin_lock(&wandev->dev_head_lock,&flags); WAN_LIST_FOREACH(devle, &wandev->dev_head, dev_link){ dev = WAN_DEVLE2DEV(devle); if (!dev || !(dev->flags&IFF_UP) || !wan_netif_priv(dev)){ continue; } m->count = wandev->get_map(wandev, dev, m, M_STOP_CNT(m)); } wan_spin_unlock(&wandev->dev_head_lock,&flags); wandev_mapdir_get_info_exit: PROC_ADD_RET(m); } #endif /* __LINUX__ */ #else /* * No /proc - output stubs */ int wanrouter_proc_init(void) { return 0; } void wanrouter_proc_cleanup(void) { return; } int wanrouter_proc_add(wan_device_t *wandev) { return 0; } int wanrouter_proc_delete(wan_device_t *wandev) { return 0; } int wanrouter_proc_add_protocol(wan_device_t *wandev) { return 0; } int wanrouter_proc_delete_protocol(wan_device_t *wandev) { return 0; } int wanrouter_proc_add_interface(wan_device_t* wandev, struct proc_dir_entry** dent, char* if_name, void* priv) { return 0; } int wanrouter_proc_delete_interface(wan_device_t* wandev, char* if_name) { return 0; } #endif /*============================================================================ * Write WAN device ???. * o Find WAN device associated with this node */ #ifdef LINUX_2_0 static int device_write( struct inode* inode, struct file* file, const char* buf, int count) { int err = verify_area(VERIFY_READ, buf, count); struct proc_dir_entry* dent; wan_device_t* wandev; if (err) return err; #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18) dent = inode->i_private; #else dent = inode->u.generic_ip; #endif if ((dent == NULL) || (dent->data == NULL)) return -ENODATA; wandev = dent->data; DEBUG_TEST("%s: writing %d bytes to %s...\n", name_root, count, dent->name); return 0; } #endif #if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) int proc_add_line(struct seq_file* m, char* frm, ...) { char tmp[400]; int ret = PROC_BUF_CONT; int size = 0; va_list arg; va_start(arg, frm); if (m->count && m->stop_cnt){ va_end(arg); return PROC_BUF_EXIT; } size = vsprintf(tmp, frm, arg); if (m->stop_cnt){ if (m->stop_cnt < size){ DEBUG_ERROR("!!! Error in writting in proc buffer !!!\n"); m->stop_cnt = size; } m->stop_cnt -= size; }else{ if (size < m->size - m->count){ /*vsprintf(&m->buf[m->count], frm, arg);*/ memcpy(&m->buf[m->count], tmp, size); m->count += size; /* *cnt += vsprintf(&buf[*cnt], frm, arg); */ }else{ m->stop_cnt = m->from + m->count; ret = PROC_BUF_EXIT; } } va_end(arg); return ret; } #endif #if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) #else int proc_add_line(struct seq_file* m, char* frm, ...) { #if defined(LINUX_2_6) return 0; #else char tmp[400]; int ret = PROC_BUF_CONT; int size = 0; va_list arg; va_start(arg, frm); if (m->count && m->stop_cnt){ va_end(arg); return PROC_BUF_EXIT; } size = vsprintf(tmp, frm, arg); if (m->stop_cnt){ if (m->stop_cnt < size){ DEBUG_ERROR("!!! Error in writting in proc buffer !!!\n"); m->stop_cnt = size; } m->stop_cnt -= size; }else{ if (size < m->size - m->count){ /*vsprintf(&m->buf[m->count], frm, arg);*/ memcpy(&m->buf[m->count], tmp, size); m->count += size; /* *cnt += vsprintf(&buf[*cnt], frm, arg); */ }else{ m->stop_cnt = m->from + m->count; ret = PROC_BUF_EXIT; } } va_end(arg); return ret; #endif } #endif #endif /* !__WINDOWS__ */ /* * End */