summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/net/llc_main.h3
-rw-r--r--include/net/llc_proc.h18
-rw-r--r--net/llc/Makefile2
-rw-r--r--net/llc/af_llc.c100
-rw-r--r--net/llc/llc_if.c2
-rw-r--r--net/llc/llc_mac.c3
-rw-r--r--net/llc/llc_main.c12
-rw-r--r--net/llc/llc_proc.c227
8 files changed, 260 insertions, 107 deletions
diff --git a/include/net/llc_main.h b/include/net/llc_main.h
index 434e86044dec..0e0d39742a2e 100644
--- a/include/net/llc_main.h
+++ b/include/net/llc_main.h
@@ -57,10 +57,11 @@ extern struct llc_sap *llc_sap_alloc(void);
extern void llc_sap_save(struct llc_sap *sap);
extern void llc_free_sap(struct llc_sap *sap);
extern struct llc_sap *llc_sap_find(u8 lsap);
-extern struct llc_station *llc_station_get(void);
extern void llc_station_state_process(struct llc_station *station,
struct sk_buff *skb);
extern void llc_station_send_pdu(struct llc_station *station,
struct sk_buff *skb);
extern struct sk_buff *llc_alloc_frame(void);
+
+extern struct llc_station llc_main_station;
#endif /* LLC_MAIN_H */
diff --git a/include/net/llc_proc.h b/include/net/llc_proc.h
new file mode 100644
index 000000000000..c6e7306aa8c3
--- /dev/null
+++ b/include/net/llc_proc.h
@@ -0,0 +1,18 @@
+#ifndef LLC_PROC_H
+#define LLC_PROC_H
+/*
+ * Copyright (c) 1997 by Procom Technology, Inc.
+ * 2002 by Arnaldo Carvalho de Melo <acme@conectiva.com.br>
+ *
+ * This program can be redistributed or modified under the terms of the
+ * GNU General Public License as published by the Free Software Foundation.
+ * This program is distributed without any warranty or implied warranty
+ * of merchantability or fitness for a particular purpose.
+ *
+ * See the GNU General Public License for more details.
+ */
+
+extern int llc_proc_init(void);
+extern void llc_proc_exit(void);
+
+#endif /* LLC_PROC_H */
diff --git a/net/llc/Makefile b/net/llc/Makefile
index 05ae5f67518d..5c9a53fe6988 100644
--- a/net/llc/Makefile
+++ b/net/llc/Makefile
@@ -16,7 +16,7 @@ obj-$(CONFIG_LLC) += llc.o
llc-y := llc_if.o llc_c_ev.o llc_c_ac.o llc_mac.o llc_sap.o llc_s_st.o \
llc_main.o llc_s_ac.o llc_conn.o llc_c_st.o llc_stat.o llc_actn.o \
- llc_s_ev.o llc_evnt.o llc_pdu.o
+ llc_s_ev.o llc_evnt.o llc_pdu.o llc_proc.o
llc-$(CONFIG_LLC_UI) += af_llc.o
llc-objs := $(llc-y)
diff --git a/net/llc/af_llc.c b/net/llc/af_llc.c
index 2144915eee5b..0c99a4e6c01f 100644
--- a/net/llc/af_llc.c
+++ b/net/llc/af_llc.c
@@ -41,6 +41,7 @@
#include <net/llc_conn.h>
#include <net/llc_mac.h>
#include <net/llc_main.h>
+#include <net/llc_proc.h>
#include <linux/llc.h>
#include <linux/if_arp.h>
#include <linux/rtnetlink.h>
@@ -1027,94 +1028,6 @@ out:
return rc;
}
-#ifdef CONFIG_PROC_FS
-#define MAC_FORMATTED_SIZE 17
-static void llc_ui_format_mac(char *bf, unsigned char *mac)
-{
- sprintf(bf, "%02X:%02X:%02X:%02X:%02X:%02X",
- mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
-}
-
-/**
- * llc_ui_get_info - return info to procfs
- * @buffer: where to put the formatted output
- * @start: starting from
- * @offset: offset into buffer.
- * @length: size of the buffer
- *
- * Get the output of the local llc ui socket list to the caller.
- * Returns the length of data wrote to buffer.
- */
-static int llc_ui_get_info(char *buffer, char **start, off_t offset, int length)
-{
- off_t pos = 0;
- off_t begin = 0;
- struct llc_sap *sap;
- struct sock *sk;
- struct list_head *sap_entry;
- struct llc_station *station = llc_station_get();
- int len = sprintf(buffer, "SKt Mc local_mac_sap "
- "remote_mac_sap tx_queue rx_queue st uid "
- "link\n");
-
- /* Output the LLC socket data for the /proc filesystem */
- read_lock_bh(&station->sap_list.lock);
- list_for_each(sap_entry, &station->sap_list.list) {
- sap = list_entry(sap_entry, struct llc_sap, node);
-
- read_lock_bh(&sap->sk_list.lock);
- for (sk = sap->sk_list.list; sk; sk = sk->next) {
- struct llc_opt *llc = llc_sk(sk);
-
- len += sprintf(buffer + len, "%2X %2X ", sk->type,
- !llc_mac_null(llc->addr.sllc_mmac));
- if (llc->dev && llc_mac_null(llc->addr.sllc_mmac))
- llc_ui_format_mac(buffer + len,
- llc->dev->dev_addr);
- else {
- if (!llc_mac_null(llc->addr.sllc_mmac))
- llc_ui_format_mac(buffer + len,
- llc->addr.sllc_mmac);
- else
- sprintf(buffer + len,
- "00:00:00:00:00:00");
- }
- len += MAC_FORMATTED_SIZE;
- len += sprintf(buffer + len, "@%02X ", sap->laddr.lsap);
- llc_ui_format_mac(buffer + len, llc->addr.sllc_dmac);
- len += MAC_FORMATTED_SIZE;
- len += sprintf(buffer + len,
- "@%02X %8d %8d %2d %3d ",
- llc->addr.sllc_dsap,
- atomic_read(&sk->wmem_alloc),
- atomic_read(&sk->rmem_alloc),
- sk->state,
- sk->socket ?
- SOCK_INODE(sk->socket)->i_uid : -1);
- len += sprintf(buffer + len, "%4d\n", llc->link);
- /* Are we still dumping unwanted data then discard the record */
- pos = begin + len;
-
- if (pos < offset) {
- len = 0; /* Keep dumping into the buffer start */
- begin = pos;
- }
- if (pos > offset + length) /* We have dumped enough */
- break;
- }
- read_unlock_bh(&sap->sk_list.lock);
- }
- read_unlock_bh(&station->sap_list.lock);
-
- /* The data in question runs from begin to begin + len */
- *start = buffer + offset - begin; /* Start of wanted data */
- len -= offset - begin; /* Remove unwanted header data from length */
- if (len > length)
- len = length; /* Remove unwanted tail data from length */
- return len;
-}
-#endif /* CONFIG_PROC_FS */
-
static struct net_proto_family llc_ui_family_ops = {
.family = PF_LLC,
.create = llc_ui_create,
@@ -1145,15 +1058,20 @@ static char llc_ui_banner[] __initdata =
int __init llc_ui_init(void)
{
+ int rc = llc_proc_init();
+
+ if (rc)
+ goto out;
llc_ui_sap_last_autoport = LLC_SAP_DYN_START;
sock_register(&llc_ui_family_ops);
- proc_net_create("llc", 0, llc_ui_get_info);
printk(llc_ui_banner);
- return 0;
+ rc = 0;
+out:
+ return rc;
}
void __exit llc_ui_exit(void)
{
- proc_net_remove("llc");
sock_unregister(PF_LLC);
+ llc_proc_exit();
}
diff --git a/net/llc/llc_if.c b/net/llc/llc_if.c
index 1f1d241732a6..ffc0771f69e4 100644
--- a/net/llc/llc_if.c
+++ b/net/llc/llc_if.c
@@ -56,7 +56,7 @@ struct llc_sap *llc_sap_open(u8 lsap, int (*func)(struct sk_buff *skb,
/* allocated a SAP; initialize it and clear out its memory pool */
sap->laddr.lsap = lsap;
sap->rcv_func = func;
- sap->station = llc_station_get();
+ sap->station = &llc_main_station;
/* initialized SAP; add it to list of SAPs this station manages */
llc_sap_save(sap);
out:
diff --git a/net/llc/llc_mac.c b/net/llc/llc_mac.c
index ae97f73a607b..3f53410df740 100644
--- a/net/llc/llc_mac.c
+++ b/net/llc/llc_mac.c
@@ -197,12 +197,11 @@ static void fix_up_incoming_skb(struct sk_buff *skb)
*/
static void llc_station_rcv(struct sk_buff *skb)
{
- struct llc_station *station = llc_station_get();
struct llc_station_state_ev *ev = llc_station_ev(skb);
ev->type = LLC_STATION_EV_TYPE_PDU;
ev->reason = 0;
- llc_station_state_process(station, skb);
+ llc_station_state_process(&llc_main_station, skb);
}
diff --git a/net/llc/llc_main.c b/net/llc/llc_main.c
index f7b54e15882d..a8167171dc6b 100644
--- a/net/llc/llc_main.c
+++ b/net/llc/llc_main.c
@@ -50,7 +50,7 @@ static struct llc_station_state_trans *
struct sk_buff *skb);
static int llc_rtn_all_conns(struct llc_sap *sap);
-static struct llc_station llc_main_station; /* only one of its kind */
+struct llc_station llc_main_station; /* only one of its kind */
#undef LLC_REFCNT_DEBUG
#ifdef LLC_REFCNT_DEBUG
@@ -340,16 +340,6 @@ static int llc_rtn_all_conns(struct llc_sap *sap)
}
/**
- * llc_station_get - get addr of global station.
- *
- * Returns address of a place to copy the global station to it.
- */
-struct llc_station *llc_station_get(void)
-{
- return &llc_main_station;
-}
-
-/**
* llc_station_state_process: queue event and try to process queue.
* @station: Address of the station
* @skb: Address of the event
diff --git a/net/llc/llc_proc.c b/net/llc/llc_proc.c
new file mode 100644
index 000000000000..e9f08b48dc68
--- /dev/null
+++ b/net/llc/llc_proc.c
@@ -0,0 +1,227 @@
+/*
+ * proc_llc.c - proc interface for LLC
+ *
+ * Copyright (c) 2001 by Jay Schulist <jschlst@samba.org>
+ * 2002 by Arnaldo Carvalho de Melo <acme@conectiva.com.br>
+ *
+ * This program can be redistributed or modified under the terms of the
+ * GNU General Public License as published by the Free Software Foundation.
+ * This program is distributed without any warranty or implied warranty
+ * of merchantability or fitness for a particular purpose.
+ *
+ * See the GNU General Public License for more details.
+ */
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/socket.h>
+#include <linux/sockios.h>
+#include <asm/uaccess.h>
+#include <asm/ioctls.h>
+#include <linux/proc_fs.h>
+#include <linux/in.h>
+#include <linux/tcp.h>
+#include <linux/netdevice.h>
+#include <linux/inetdevice.h>
+#include <linux/errno.h>
+#include <net/sock.h>
+#include <net/llc_if.h>
+#include <net/llc_sap.h>
+#include <net/llc_pdu.h>
+#include <net/llc_conn.h>
+#include <net/llc_mac.h>
+#include <net/llc_main.h>
+#include <linux/llc.h>
+#include <linux/if_arp.h>
+#include <linux/rtnetlink.h>
+#include <linux/init.h>
+#include <linux/seq_file.h>
+
+#ifdef CONFIG_PROC_FS
+static void llc_ui_format_mac(struct seq_file *seq, unsigned char *mac)
+{
+ seq_printf(seq, "%02X:%02X:%02X:%02X:%02X:%02X",
+ mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+}
+
+static __inline__ struct sock *llc_get_sk_idx(loff_t pos)
+{
+ struct list_head *sap_entry;
+ struct llc_sap *sap;
+ struct sock *sk = NULL;
+
+ list_for_each(sap_entry, &llc_main_station.sap_list.list) {
+ sap = list_entry(sap_entry, struct llc_sap, node);
+
+ read_lock_bh(&sap->sk_list.lock);
+ for (sk = sap->sk_list.list; pos && sk; sk = sk->next)
+ --pos;
+ if (!pos) {
+ if (!sk)
+ read_unlock_bh(&sap->sk_list.lock);
+ break;
+ }
+ read_unlock_bh(&sap->sk_list.lock);
+ }
+ return sk;
+}
+
+static void *llc_seq_start(struct seq_file *seq, loff_t *pos)
+{
+ loff_t l = *pos;
+
+ read_lock_bh(&llc_main_station.sap_list.lock);
+ if (!l)
+ return (void *)1;
+ return llc_get_sk_idx(--l);
+}
+
+static void *llc_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+ struct sock* sk;
+ struct llc_opt *llc;
+ struct llc_sap *sap;
+
+ ++*pos;
+ if (v == (void *)1) {
+ if (list_empty(&llc_main_station.sap_list.list)) {
+ sk = NULL;
+ goto out;
+ }
+ sap = list_entry(llc_main_station.sap_list.list.next,
+ struct llc_sap, node);
+
+ read_lock_bh(&sap->sk_list.lock);
+ sk = sap->sk_list.list;
+ goto out;
+ }
+ sk = v;
+ if (sk->next) {
+ sk = sk->next;
+ goto out;
+ }
+ llc = llc_sk(sk);
+ sap = llc->sap;
+ read_unlock_bh(&sap->sk_list.lock);
+ sk = NULL;
+ for (;;) {
+ if (sap->node.next == &llc_main_station.sap_list.list)
+ break;
+ sap = list_entry(sap->node.next, struct llc_sap, node);
+ read_lock_bh(&sap->sk_list.lock);
+ if (sap->sk_list.list) {
+ sk = sap->sk_list.list;
+ break;
+ }
+ read_unlock_bh(&sap->sk_list.lock);
+ }
+out:
+ return sk;
+}
+
+static void llc_seq_stop(struct seq_file *seq, void *v)
+{
+ read_unlock_bh(&llc_main_station.sap_list.lock);
+}
+
+static int llc_seq_show(struct seq_file *seq, void *v)
+{
+ struct sock* sk;
+ struct llc_opt *llc;
+
+ if (v == (void *)1) {
+ seq_puts(seq, "SKt Mc local_mac_sap remote_mac_sap "
+ " tx_queue rx_queue st uid link\n");
+ goto out;
+ }
+ sk = v;
+ llc = llc_sk(sk);
+
+ seq_printf(seq, "%2X %2X ", sk->type,
+ !llc_mac_null(llc->addr.sllc_mmac));
+
+ if (llc->dev && llc_mac_null(llc->addr.sllc_mmac))
+ llc_ui_format_mac(seq, llc->dev->dev_addr);
+ else if (!llc_mac_null(llc->addr.sllc_mmac))
+ llc_ui_format_mac(seq, llc->addr.sllc_mmac);
+ else
+ seq_printf(seq, "00:00:00:00:00:00");
+ seq_printf(seq, "@%02X ", llc->sap->laddr.lsap);
+ llc_ui_format_mac(seq, llc->addr.sllc_dmac);
+ seq_printf(seq, "@%02X %8d %8d %2d %3d %4d\n", llc->addr.sllc_dsap,
+ atomic_read(&sk->wmem_alloc), atomic_read(&sk->rmem_alloc),
+ sk->state, sk->socket ? SOCK_INODE(sk->socket)->i_uid : -1,
+ llc->link);
+out:
+ return 0;
+}
+
+struct seq_operations llc_seq_ops = {
+ .start = llc_seq_start,
+ .next = llc_seq_next,
+ .stop = llc_seq_stop,
+ .show = llc_seq_show,
+};
+
+static int llc_seq_open(struct inode *inode, struct file *file)
+{
+ return seq_open(file, &llc_seq_ops);
+}
+
+static int llc_proc_perms(struct inode* inode, int op)
+{
+ return 0;
+}
+
+static struct file_operations llc_seq_fops = {
+ .open = llc_seq_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
+static struct inode_operations llc_seq_inode = {
+ .permission = llc_proc_perms,
+};
+
+static struct proc_dir_entry *llc_proc_dir;
+
+int __init llc_proc_init(void)
+{
+ int rc = -ENOMEM;
+ struct proc_dir_entry *p;
+
+ llc_proc_dir = proc_mkdir("llc", proc_net);
+ if (!llc_proc_dir)
+ goto out;
+
+ p = create_proc_entry("socket", 0, llc_proc_dir);
+ if (!p)
+ goto out_socket;
+
+ p->proc_fops = &llc_seq_fops;
+ p->proc_iops = &llc_seq_inode;
+ rc = 0;
+out:
+ return rc;
+out_socket:
+ remove_proc_entry("llc", proc_net);
+ goto out;
+}
+
+void __exit llc_proc_exit(void)
+{
+ remove_proc_entry("socket", llc_proc_dir);
+ remove_proc_entry("llc", proc_net);
+}
+#else /* CONFIG_PROC_FS */
+int __init llc_proc_init(void)
+{
+ return 0;
+}
+
+void __exit llc_proc_exit(void)
+{
+}
+#endif /* CONFIG_PROC_FS */