0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <net/6lowpan.h>
0010
0011 #include "6lowpan_i.h"
0012
0013 #define LOWPAN_DEBUGFS_CTX_PFX_NUM_ARGS 8
0014
0015 static struct dentry *lowpan_debugfs;
0016
0017 static int lowpan_ctx_flag_active_set(void *data, u64 val)
0018 {
0019 struct lowpan_iphc_ctx *ctx = data;
0020
0021 if (val != 0 && val != 1)
0022 return -EINVAL;
0023
0024 if (val)
0025 set_bit(LOWPAN_IPHC_CTX_FLAG_ACTIVE, &ctx->flags);
0026 else
0027 clear_bit(LOWPAN_IPHC_CTX_FLAG_ACTIVE, &ctx->flags);
0028
0029 return 0;
0030 }
0031
0032 static int lowpan_ctx_flag_active_get(void *data, u64 *val)
0033 {
0034 *val = lowpan_iphc_ctx_is_active(data);
0035 return 0;
0036 }
0037
0038 DEFINE_DEBUGFS_ATTRIBUTE(lowpan_ctx_flag_active_fops,
0039 lowpan_ctx_flag_active_get,
0040 lowpan_ctx_flag_active_set, "%llu\n");
0041
0042 static int lowpan_ctx_flag_c_set(void *data, u64 val)
0043 {
0044 struct lowpan_iphc_ctx *ctx = data;
0045
0046 if (val != 0 && val != 1)
0047 return -EINVAL;
0048
0049 if (val)
0050 set_bit(LOWPAN_IPHC_CTX_FLAG_COMPRESSION, &ctx->flags);
0051 else
0052 clear_bit(LOWPAN_IPHC_CTX_FLAG_COMPRESSION, &ctx->flags);
0053
0054 return 0;
0055 }
0056
0057 static int lowpan_ctx_flag_c_get(void *data, u64 *val)
0058 {
0059 *val = lowpan_iphc_ctx_is_compression(data);
0060 return 0;
0061 }
0062
0063 DEFINE_DEBUGFS_ATTRIBUTE(lowpan_ctx_flag_c_fops, lowpan_ctx_flag_c_get,
0064 lowpan_ctx_flag_c_set, "%llu\n");
0065
0066 static int lowpan_ctx_plen_set(void *data, u64 val)
0067 {
0068 struct lowpan_iphc_ctx *ctx = data;
0069 struct lowpan_iphc_ctx_table *t =
0070 container_of(ctx, struct lowpan_iphc_ctx_table, table[ctx->id]);
0071
0072 if (val > 128)
0073 return -EINVAL;
0074
0075 spin_lock_bh(&t->lock);
0076 ctx->plen = val;
0077 spin_unlock_bh(&t->lock);
0078
0079 return 0;
0080 }
0081
0082 static int lowpan_ctx_plen_get(void *data, u64 *val)
0083 {
0084 struct lowpan_iphc_ctx *ctx = data;
0085 struct lowpan_iphc_ctx_table *t =
0086 container_of(ctx, struct lowpan_iphc_ctx_table, table[ctx->id]);
0087
0088 spin_lock_bh(&t->lock);
0089 *val = ctx->plen;
0090 spin_unlock_bh(&t->lock);
0091 return 0;
0092 }
0093
0094 DEFINE_DEBUGFS_ATTRIBUTE(lowpan_ctx_plen_fops, lowpan_ctx_plen_get,
0095 lowpan_ctx_plen_set, "%llu\n");
0096
0097 static int lowpan_ctx_pfx_show(struct seq_file *file, void *offset)
0098 {
0099 struct lowpan_iphc_ctx *ctx = file->private;
0100 struct lowpan_iphc_ctx_table *t =
0101 container_of(ctx, struct lowpan_iphc_ctx_table, table[ctx->id]);
0102
0103 spin_lock_bh(&t->lock);
0104 seq_printf(file, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
0105 be16_to_cpu(ctx->pfx.s6_addr16[0]),
0106 be16_to_cpu(ctx->pfx.s6_addr16[1]),
0107 be16_to_cpu(ctx->pfx.s6_addr16[2]),
0108 be16_to_cpu(ctx->pfx.s6_addr16[3]),
0109 be16_to_cpu(ctx->pfx.s6_addr16[4]),
0110 be16_to_cpu(ctx->pfx.s6_addr16[5]),
0111 be16_to_cpu(ctx->pfx.s6_addr16[6]),
0112 be16_to_cpu(ctx->pfx.s6_addr16[7]));
0113 spin_unlock_bh(&t->lock);
0114
0115 return 0;
0116 }
0117
0118 static int lowpan_ctx_pfx_open(struct inode *inode, struct file *file)
0119 {
0120 return single_open(file, lowpan_ctx_pfx_show, inode->i_private);
0121 }
0122
0123 static ssize_t lowpan_ctx_pfx_write(struct file *fp,
0124 const char __user *user_buf, size_t count,
0125 loff_t *ppos)
0126 {
0127 char buf[128] = {};
0128 struct seq_file *file = fp->private_data;
0129 struct lowpan_iphc_ctx *ctx = file->private;
0130 struct lowpan_iphc_ctx_table *t =
0131 container_of(ctx, struct lowpan_iphc_ctx_table, table[ctx->id]);
0132 int status = count, n, i;
0133 unsigned int addr[8];
0134
0135 if (copy_from_user(&buf, user_buf, min_t(size_t, sizeof(buf) - 1,
0136 count))) {
0137 status = -EFAULT;
0138 goto out;
0139 }
0140
0141 n = sscanf(buf, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x",
0142 &addr[0], &addr[1], &addr[2], &addr[3], &addr[4],
0143 &addr[5], &addr[6], &addr[7]);
0144 if (n != LOWPAN_DEBUGFS_CTX_PFX_NUM_ARGS) {
0145 status = -EINVAL;
0146 goto out;
0147 }
0148
0149 spin_lock_bh(&t->lock);
0150 for (i = 0; i < 8; i++)
0151 ctx->pfx.s6_addr16[i] = cpu_to_be16(addr[i] & 0xffff);
0152 spin_unlock_bh(&t->lock);
0153
0154 out:
0155 return status;
0156 }
0157
0158 static const struct file_operations lowpan_ctx_pfx_fops = {
0159 .open = lowpan_ctx_pfx_open,
0160 .read = seq_read,
0161 .write = lowpan_ctx_pfx_write,
0162 .llseek = seq_lseek,
0163 .release = single_release,
0164 };
0165
0166 static void lowpan_dev_debugfs_ctx_init(struct net_device *dev,
0167 struct dentry *ctx, u8 id)
0168 {
0169 struct lowpan_dev *ldev = lowpan_dev(dev);
0170 struct dentry *root;
0171 char buf[32];
0172
0173 if (WARN_ON_ONCE(id >= LOWPAN_IPHC_CTX_TABLE_SIZE))
0174 return;
0175
0176 sprintf(buf, "%d", id);
0177
0178 root = debugfs_create_dir(buf, ctx);
0179
0180 debugfs_create_file("active", 0644, root, &ldev->ctx.table[id],
0181 &lowpan_ctx_flag_active_fops);
0182
0183 debugfs_create_file("compression", 0644, root, &ldev->ctx.table[id],
0184 &lowpan_ctx_flag_c_fops);
0185
0186 debugfs_create_file("prefix", 0644, root, &ldev->ctx.table[id],
0187 &lowpan_ctx_pfx_fops);
0188
0189 debugfs_create_file("prefix_len", 0644, root, &ldev->ctx.table[id],
0190 &lowpan_ctx_plen_fops);
0191 }
0192
0193 static int lowpan_context_show(struct seq_file *file, void *offset)
0194 {
0195 struct lowpan_iphc_ctx_table *t = file->private;
0196 int i;
0197
0198 seq_printf(file, "%3s|%-43s|%c\n", "cid", "prefix", 'C');
0199 seq_puts(file, "-------------------------------------------------\n");
0200
0201 spin_lock_bh(&t->lock);
0202 for (i = 0; i < LOWPAN_IPHC_CTX_TABLE_SIZE; i++) {
0203 if (!lowpan_iphc_ctx_is_active(&t->table[i]))
0204 continue;
0205
0206 seq_printf(file, "%3d|%39pI6c/%-3d|%d\n", t->table[i].id,
0207 &t->table[i].pfx, t->table[i].plen,
0208 lowpan_iphc_ctx_is_compression(&t->table[i]));
0209 }
0210 spin_unlock_bh(&t->lock);
0211
0212 return 0;
0213 }
0214 DEFINE_SHOW_ATTRIBUTE(lowpan_context);
0215
0216 static int lowpan_short_addr_get(void *data, u64 *val)
0217 {
0218 struct wpan_dev *wdev = data;
0219
0220 rtnl_lock();
0221 *val = le16_to_cpu(wdev->short_addr);
0222 rtnl_unlock();
0223
0224 return 0;
0225 }
0226
0227 DEFINE_DEBUGFS_ATTRIBUTE(lowpan_short_addr_fops, lowpan_short_addr_get, NULL,
0228 "0x%04llx\n");
0229
0230 static void lowpan_dev_debugfs_802154_init(const struct net_device *dev,
0231 struct lowpan_dev *ldev)
0232 {
0233 struct dentry *root;
0234
0235 if (!lowpan_is_ll(dev, LOWPAN_LLTYPE_IEEE802154))
0236 return;
0237
0238 root = debugfs_create_dir("ieee802154", ldev->iface_debugfs);
0239
0240 debugfs_create_file("short_addr", 0444, root,
0241 lowpan_802154_dev(dev)->wdev->ieee802154_ptr,
0242 &lowpan_short_addr_fops);
0243 }
0244
0245 void lowpan_dev_debugfs_init(struct net_device *dev)
0246 {
0247 struct lowpan_dev *ldev = lowpan_dev(dev);
0248 struct dentry *contexts;
0249 int i;
0250
0251
0252 ldev->iface_debugfs = debugfs_create_dir(dev->name, lowpan_debugfs);
0253
0254 contexts = debugfs_create_dir("contexts", ldev->iface_debugfs);
0255
0256 debugfs_create_file("show", 0644, contexts, &lowpan_dev(dev)->ctx,
0257 &lowpan_context_fops);
0258
0259 for (i = 0; i < LOWPAN_IPHC_CTX_TABLE_SIZE; i++)
0260 lowpan_dev_debugfs_ctx_init(dev, contexts, i);
0261
0262 lowpan_dev_debugfs_802154_init(dev, ldev);
0263 }
0264
0265 void lowpan_dev_debugfs_exit(struct net_device *dev)
0266 {
0267 debugfs_remove_recursive(lowpan_dev(dev)->iface_debugfs);
0268 }
0269
0270 void __init lowpan_debugfs_init(void)
0271 {
0272 lowpan_debugfs = debugfs_create_dir("6lowpan", NULL);
0273 }
0274
0275 void lowpan_debugfs_exit(void)
0276 {
0277 debugfs_remove_recursive(lowpan_debugfs);
0278 }