j1939: proc: re-add proc interface
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
diff --git a/Documentation/networking/j1939.txt b/Documentation/networking/j1939.txt
index d2cdfa9..a0503ff 100644
--- a/Documentation/networking/j1939.txt
+++ b/Documentation/networking/j1939.txt
@@ -38,7 +38,13 @@
6 can-j1939 SYSCTL
- 7 Credits
+ 7 can-j1939 procfs interface
+ 7.1 /proc/net/can-j1939/ecu
+ 7.2 /proc/net/can-j1939/filter
+ 7.3 /proc/net/can-j1939/sock
+ 7.4 /proc/net/can-j1939/transport
+
+ 8 Credits
============================================================================
@@ -468,7 +474,50 @@
See section "SAE J1939" in "Documentation/sysctl/net.txt".
-7. Credits
+7. /proc/net/can-j1939 Interface.
+--------------------------------
+
+ Files giving you a view on the in-kernel operation of J1939 are located at:
+ /proc/net/j1939.
+
+7.1 /proc/net/can-j1939/ecu
+
+ This file gives an overview of the known ECU's to the kernel.
+ - iface : network interface they operate on.
+ - SA : current address.
+ - name : 64bit NAME
+ - flags : 'L' = local, 'R' = remote
+
+7.2 /proc/net/can-j1939/filter
+
+7.3 /proc/net/can-j1939/sock
+
+ This file gives a list of all j1939 sockets currently open.
+ - iface : network interface
+ - flags :
+ 'b' : bound
+ 'c' : connected
+ 'P' : PROMISC
+ 'o' : RECV_OWN
+ 'd' : RECV_DEST
+ 'p' : RECV_PRIO
+ - local: [NAME],SA
+ - remote: [NAME]/MASK,DA
+ - pgn : PGN
+ - prio : priority
+ - pending : # packets pending (see MSG_SYN on 4.2.1)
+
+7.4 /proc/net/can-j1939/transport
+
+ This file shows a list of pending transport sessions
+ - iface
+ - src : XX (addr) or XXXXXXXXXXXXXXXX (name)
+ - dst : XX or XXXXXXXXXXXXXXXX or '-' (broadcast)
+ - pgn :
+ - done/total : current # transferred bytes / total
+
+
+8. Credits
--------------------------------
Kurt Van Dijck (j1939 core, transport protocol, API)
diff --git a/net/can/j1939/j1939-priv.h b/net/can/j1939/j1939-priv.h
index 67a8a06..f799350 100644
--- a/net/can/j1939/j1939-priv.h
+++ b/net/can/j1939/j1939-priv.h
@@ -18,6 +18,7 @@
#include <linux/kref.h>
#include <linux/list.h>
#include <linux/module.h>
+#include <linux/proc_fs.h>
#include <linux/can/can-ml.h>
#include <linux/can/j1939.h>
@@ -181,6 +182,8 @@ struct j1939_ecu *j1939_ecu_find_by_name(name_t name, int ifindex);
/* find_by_name, with kref & read_lock taken */
struct j1939_ecu *j1939_ecu_find_priv_default_tx(int ifindex, name_t *pname,
u8 *paddr);
+extern struct proc_dir_entry *j1939_procdir;
+
struct j1939_addr {
name_t src_name;
name_t dst_name;
diff --git a/net/can/j1939/main.c b/net/can/j1939/main.c
index 1412fc2..14932f7 100644
--- a/net/can/j1939/main.c
+++ b/net/can/j1939/main.c
@@ -31,6 +31,9 @@ MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("EIA Electronics (Kurt Van Dijck & Pieter Beyens)");
MODULE_ALIAS("can-proto-" __stringify(CAN_J1939));
+static const char j1939_procname[] = "can-j1939";
+struct proc_dir_entry *j1939_procdir;
+
/* LOWLEVEL CAN interface */
/* CAN_HDR: #bytes before can_frame data part */
@@ -347,6 +350,84 @@ static struct notifier_block j1939_netdev_notifier = {
.notifier_call = j1939_netdev_notify,
};
+/* proc access to the addr+name database */
+static int j1939_proc_show_addr(struct seq_file *sqf, void *v)
+{
+ struct net_device *netdev;
+ struct j1939_priv *priv;
+ int j;
+
+ seq_puts(sqf, "iface\tsa\t#users\n");
+ rcu_read_lock();
+ for_each_netdev_rcu(&init_net, netdev) {
+ priv = j1939_priv_get(netdev);
+ if (!priv)
+ continue;
+ read_lock_bh(&priv->lock);
+ for (j = 0; j < 0xfe; ++j) {
+ if (!priv->ents[j].nusers)
+ continue;
+ seq_printf(sqf, "%s\t%02x\t%i\n",
+ netdev->name, j, priv->ents[j].nusers);
+ }
+ read_unlock_bh(&priv->lock);
+ j1939_priv_put(priv);
+ }
+ rcu_read_unlock();
+ return 0;
+}
+
+static int j1939_proc_show_name(struct seq_file *sqf, void *v)
+{
+ struct net_device *netdev;
+ struct j1939_priv *priv;
+ struct j1939_ecu *ecu;
+
+ seq_puts(sqf, "iface\tname\tsa\t#users\n");
+ rcu_read_lock();
+ for_each_netdev_rcu(&init_net, netdev) {
+ priv = j1939_priv_get(netdev);
+ if (!priv)
+ continue;
+ read_lock_bh(&priv->lock);
+ list_for_each_entry(ecu, &priv->ecus, list)
+ seq_printf(sqf, "%s\t%016llx\t%02x%s\t%i\n",
+ netdev->name, ecu->name, ecu->sa,
+ (priv->ents[ecu->sa].ecu == ecu) ? "" : "?",
+ ecu->nusers);
+ read_unlock_bh(&priv->lock);
+ j1939_priv_put(priv);
+ }
+ rcu_read_unlock();
+ return 0;
+}
+
+static int j1939_proc_open_addr(struct inode *inode, struct file *file)
+{
+ return single_open(file, j1939_proc_show_addr, NULL);
+}
+
+static int j1939_proc_open_name(struct inode *inode, struct file *file)
+{
+ return single_open(file, j1939_proc_show_name, NULL);
+}
+
+static const struct file_operations j1939_proc_ops_addr = {
+ .owner = THIS_MODULE,
+ .open = j1939_proc_open_addr,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static const struct file_operations j1939_proc_ops_name = {
+ .owner = THIS_MODULE,
+ .open = j1939_proc_open_name,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
/* MODULE interface */
static __init int j1939_module_init(void)
{
@@ -354,6 +435,11 @@ static __init int j1939_module_init(void)
pr_info("can: SAE J1939\n");
+ /* create /proc/net/can directory */
+ j1939_procdir = proc_mkdir(j1939_procname, init_net.proc_net);
+ if (!j1939_procdir)
+ return -EINVAL;
+
ret = register_netdevice_notifier(&j1939_netdev_notifier);
if (ret)
goto fail_notifier;
@@ -367,23 +453,38 @@ static __init int j1939_module_init(void)
if (ret < 0)
goto fail_tp;
+ if (!proc_create("addr", 0444, j1939_procdir, &j1939_proc_ops_addr))
+ goto fail_addr;
+ if (!proc_create("name", 0444, j1939_procdir, &j1939_proc_ops_name))
+ goto fail_name;
return 0;
+ fail_name:
+ remove_proc_entry("addr", j1939_procdir);
+ fail_addr:
+ j1939tp_module_exit();
fail_tp:
can_proto_unregister(&j1939_can_proto);
fail_sk:
unregister_netdevice_notifier(&j1939_netdev_notifier);
fail_notifier:
+ proc_remove(j1939_procdir);
+ j1939_procdir = NULL;
return ret;
}
static __exit void j1939_module_exit(void)
{
+ remove_proc_entry("name", j1939_procdir);
+ remove_proc_entry("addr", j1939_procdir);
j1939tp_module_exit();
can_proto_unregister(&j1939_can_proto);
unregister_netdevice_notifier(&j1939_netdev_notifier);
+
+ proc_remove(j1939_procdir);
+ j1939_procdir = NULL;
}
module_init(j1939_module_init);
diff --git a/net/can/j1939/transport.c b/net/can/j1939/transport.c
index 183328f..944016c 100644
--- a/net/can/j1939/transport.c
+++ b/net/can/j1939/transport.c
@@ -1348,6 +1348,53 @@ int j1939tp_rmdev_notifier(struct net_device *netdev)
return NOTIFY_DONE;
}
+/* PROC */
+static int j1939tp_proc_show_session(struct seq_file *sqf,
+ struct session *session)
+{
+ seq_printf(sqf, "%i", session->skb_iif);
+ if (session->cb->addr.src_name)
+ seq_printf(sqf, "\t%016llx", session->cb->addr.src_name);
+ else
+ seq_printf(sqf, "\t%02x", session->cb->addr.sa);
+ if (session->cb->addr.dst_name)
+ seq_printf(sqf, "\t%016llx", session->cb->addr.dst_name);
+ else if (j1939_address_is_unicast(session->cb->addr.da))
+ seq_printf(sqf, "\t%02x", session->cb->addr.da);
+ else
+ seq_puts(sqf, "\t-");
+ seq_printf(sqf, "\t%05x\t%u/%u\n", session->cb->addr.pgn,
+ session->pkt.done * 7, session->skb->len);
+ return 0;
+}
+
+static int j1939tp_proc_show(struct seq_file *sqf, void *v)
+{
+ struct session *session;
+
+ seq_puts(sqf, "iface\tsrc\tdst\tpgn\tdone/total\n");
+ j1939_sessionlist_lock();
+ list_for_each_entry(session, &tp_sessionq, list)
+ j1939tp_proc_show_session(sqf, session);
+ list_for_each_entry(session, &tp_extsessionq, list)
+ j1939tp_proc_show_session(sqf, session);
+ j1939_sessionlist_unlock();
+ return 0;
+}
+
+static int j1939tp_proc_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, j1939tp_proc_show, NULL);
+}
+
+static const struct file_operations j1939tp_proc_ops = {
+ .owner = THIS_MODULE,
+ .open = j1939tp_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
static struct ctl_table canj1939_sysctl_table[] = {
{
.procname = "transport_burst_count",
@@ -1399,11 +1446,15 @@ static struct ctl_table_header *sysctl_hdr;
/* module init */
int __init j1939tp_module_init(void)
{
- sysctl_hdr = register_net_sysctl(&init_net, "net/can-j1939",
- canj1939_sysctl_table);
- if (!sysctl_hdr)
+ if (!proc_create("transport", 0444, j1939_procdir, &j1939tp_proc_ops))
return -ENOMEM;
+ sysctl_hdr = register_net_sysctl(&init_net, "net/can-j1939",
+ canj1939_sysctl_table);
+ if (!sysctl_hdr) {
+ remove_proc_entry("transport", j1939_procdir);
+ return -ENOMEM;
+ }
return 0;
}
@@ -1414,6 +1465,7 @@ void j1939tp_module_exit(void)
wake_up_all(&tp_wait);
unregister_net_sysctl_table(sysctl_hdr);
+ remove_proc_entry("transport", j1939_procdir);
j1939_sessionlist_lock();
list_for_each_entry_safe(session, saved, &tp_extsessionq, list) {
list_del_init(&session->list);