6lowpan: iphc: add support for stateful compression

This patch introduce support for IPHC stateful address compression. It
will offer the context table via one debugfs entry.
This debugfs has and directory for each cid entry for the context table.
Inside each cid directory there exists the following files:

 - "active": If the entry is added or deleted. The context table is
   original a list implementation, this flag will indicate if the
   context is part of list or not.
 - "prefix": The ipv6 prefix.
 - "prefix_length": The prefix length for the prefix.
 - "compression": The compression flag according RFC6775.

This part should be moved into sysfs after some testing time.

Also the debugfs entry contains a "show" file which is a pretty-printout
for the current context table information.

Reviewed-by: Stefan Schmidt <stefan@osg.samsung.com>
Signed-off-by: Alexander Aring <aar@pengutronix.de>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Tento commit je obsažen v:
Alexander Aring
2016-02-22 09:13:54 +01:00
odevzdal Marcel Holtmann
rodič aef00c15b8
revize 5609c185f2
4 změnil soubory, kde provedl 676 přidání a 60 odebrání

Zobrazit soubor

@@ -16,19 +16,266 @@
#include "6lowpan_i.h"
#define LOWPAN_DEBUGFS_CTX_PFX_NUM_ARGS 8
static struct dentry *lowpan_debugfs;
static int lowpan_ctx_flag_active_set(void *data, u64 val)
{
struct lowpan_iphc_ctx *ctx = data;
if (val != 0 && val != 1)
return -EINVAL;
if (val)
set_bit(LOWPAN_IPHC_CTX_FLAG_ACTIVE, &ctx->flags);
else
clear_bit(LOWPAN_IPHC_CTX_FLAG_ACTIVE, &ctx->flags);
return 0;
}
static int lowpan_ctx_flag_active_get(void *data, u64 *val)
{
*val = lowpan_iphc_ctx_is_active(data);
return 0;
}
DEFINE_SIMPLE_ATTRIBUTE(lowpan_ctx_flag_active_fops,
lowpan_ctx_flag_active_get,
lowpan_ctx_flag_active_set, "%llu\n");
static int lowpan_ctx_flag_c_set(void *data, u64 val)
{
struct lowpan_iphc_ctx *ctx = data;
if (val != 0 && val != 1)
return -EINVAL;
if (val)
set_bit(LOWPAN_IPHC_CTX_FLAG_COMPRESSION, &ctx->flags);
else
clear_bit(LOWPAN_IPHC_CTX_FLAG_COMPRESSION, &ctx->flags);
return 0;
}
static int lowpan_ctx_flag_c_get(void *data, u64 *val)
{
*val = lowpan_iphc_ctx_is_compression(data);
return 0;
}
DEFINE_SIMPLE_ATTRIBUTE(lowpan_ctx_flag_c_fops, lowpan_ctx_flag_c_get,
lowpan_ctx_flag_c_set, "%llu\n");
static int lowpan_ctx_plen_set(void *data, u64 val)
{
struct lowpan_iphc_ctx *ctx = data;
struct lowpan_iphc_ctx_table *t =
container_of(ctx, struct lowpan_iphc_ctx_table, table[ctx->id]);
if (val > 128)
return -EINVAL;
spin_lock_bh(&t->lock);
ctx->plen = val;
spin_unlock_bh(&t->lock);
return 0;
}
static int lowpan_ctx_plen_get(void *data, u64 *val)
{
struct lowpan_iphc_ctx *ctx = data;
struct lowpan_iphc_ctx_table *t =
container_of(ctx, struct lowpan_iphc_ctx_table, table[ctx->id]);
spin_lock_bh(&t->lock);
*val = ctx->plen;
spin_unlock_bh(&t->lock);
return 0;
}
DEFINE_SIMPLE_ATTRIBUTE(lowpan_ctx_plen_fops, lowpan_ctx_plen_get,
lowpan_ctx_plen_set, "%llu\n");
static int lowpan_ctx_pfx_show(struct seq_file *file, void *offset)
{
struct lowpan_iphc_ctx *ctx = file->private;
struct lowpan_iphc_ctx_table *t =
container_of(ctx, struct lowpan_iphc_ctx_table, table[ctx->id]);
spin_lock_bh(&t->lock);
seq_printf(file, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
be16_to_cpu(ctx->pfx.s6_addr16[0]),
be16_to_cpu(ctx->pfx.s6_addr16[1]),
be16_to_cpu(ctx->pfx.s6_addr16[2]),
be16_to_cpu(ctx->pfx.s6_addr16[3]),
be16_to_cpu(ctx->pfx.s6_addr16[4]),
be16_to_cpu(ctx->pfx.s6_addr16[5]),
be16_to_cpu(ctx->pfx.s6_addr16[6]),
be16_to_cpu(ctx->pfx.s6_addr16[7]));
spin_unlock_bh(&t->lock);
return 0;
}
static int lowpan_ctx_pfx_open(struct inode *inode, struct file *file)
{
return single_open(file, lowpan_ctx_pfx_show, inode->i_private);
}
static ssize_t lowpan_ctx_pfx_write(struct file *fp,
const char __user *user_buf, size_t count,
loff_t *ppos)
{
char buf[128] = {};
struct seq_file *file = fp->private_data;
struct lowpan_iphc_ctx *ctx = file->private;
struct lowpan_iphc_ctx_table *t =
container_of(ctx, struct lowpan_iphc_ctx_table, table[ctx->id]);
int status = count, n, i;
unsigned int addr[8];
if (copy_from_user(&buf, user_buf, min_t(size_t, sizeof(buf) - 1,
count))) {
status = -EFAULT;
goto out;
}
n = sscanf(buf, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x",
&addr[0], &addr[1], &addr[2], &addr[3], &addr[4],
&addr[5], &addr[6], &addr[7]);
if (n != LOWPAN_DEBUGFS_CTX_PFX_NUM_ARGS) {
status = -EINVAL;
goto out;
}
spin_lock_bh(&t->lock);
for (i = 0; i < 8; i++)
ctx->pfx.s6_addr16[i] = cpu_to_be16(addr[i] & 0xffff);
spin_unlock_bh(&t->lock);
out:
return status;
}
const struct file_operations lowpan_ctx_pfx_fops = {
.open = lowpan_ctx_pfx_open,
.read = seq_read,
.write = lowpan_ctx_pfx_write,
.llseek = seq_lseek,
.release = single_release,
};
static int lowpan_dev_debugfs_ctx_init(struct net_device *dev,
struct dentry *ctx, u8 id)
{
struct lowpan_priv *lpriv = lowpan_priv(dev);
struct dentry *dentry, *root;
char buf[32];
WARN_ON_ONCE(id > LOWPAN_IPHC_CTX_TABLE_SIZE);
sprintf(buf, "%d", id);
root = debugfs_create_dir(buf, ctx);
if (!root)
return -EINVAL;
dentry = debugfs_create_file("active", 0644, root,
&lpriv->ctx.table[id],
&lowpan_ctx_flag_active_fops);
if (!dentry)
return -EINVAL;
dentry = debugfs_create_file("compression", 0644, root,
&lpriv->ctx.table[id],
&lowpan_ctx_flag_c_fops);
if (!dentry)
return -EINVAL;
dentry = debugfs_create_file("prefix", 0644, root,
&lpriv->ctx.table[id],
&lowpan_ctx_pfx_fops);
if (!dentry)
return -EINVAL;
dentry = debugfs_create_file("prefix_len", 0644, root,
&lpriv->ctx.table[id],
&lowpan_ctx_plen_fops);
if (!dentry)
return -EINVAL;
return 0;
}
static int lowpan_context_show(struct seq_file *file, void *offset)
{
struct lowpan_iphc_ctx_table *t = file->private;
int i;
seq_printf(file, "%3s|%-43s|%c\n", "cid", "prefix", 'C');
seq_puts(file, "-------------------------------------------------\n");
spin_lock_bh(&t->lock);
for (i = 0; i < LOWPAN_IPHC_CTX_TABLE_SIZE; i++) {
if (!lowpan_iphc_ctx_is_active(&t->table[i]))
continue;
seq_printf(file, "%3d|%39pI6c/%-3d|%d\n", t->table[i].id,
&t->table[i].pfx, t->table[i].plen,
lowpan_iphc_ctx_is_compression(&t->table[i]));
}
spin_unlock_bh(&t->lock);
return 0;
}
static int lowpan_context_open(struct inode *inode, struct file *file)
{
return single_open(file, lowpan_context_show, inode->i_private);
}
const struct file_operations lowpan_context_fops = {
.open = lowpan_context_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
int lowpan_dev_debugfs_init(struct net_device *dev)
{
struct lowpan_priv *lpriv = lowpan_priv(dev);
struct dentry *contexts, *dentry;
int ret, i;
/* creating the root */
lpriv->iface_debugfs = debugfs_create_dir(dev->name, lowpan_debugfs);
if (!lpriv->iface_debugfs)
goto fail;
contexts = debugfs_create_dir("contexts", lpriv->iface_debugfs);
if (!contexts)
goto remove_root;
dentry = debugfs_create_file("show", 0644, contexts,
&lowpan_priv(dev)->ctx,
&lowpan_context_fops);
if (!dentry)
goto remove_root;
for (i = 0; i < LOWPAN_IPHC_CTX_TABLE_SIZE; i++) {
ret = lowpan_dev_debugfs_ctx_init(dev, contexts, i);
if (ret < 0)
goto remove_root;
}
return 0;
remove_root:
lowpan_dev_debugfs_exit(dev);
fail:
return -EINVAL;
}