1b1815fd9SAlexander Aring /* This program is free software; you can redistribute it and/or modify 2b1815fd9SAlexander Aring * it under the terms of the GNU General Public License version 2 3b1815fd9SAlexander Aring * as published by the Free Software Foundation. 4b1815fd9SAlexander Aring * 5b1815fd9SAlexander Aring * This program is distributed in the hope that it will be useful, 6b1815fd9SAlexander Aring * but WITHOUT ANY WARRANTY; without even the implied warranty of 7b1815fd9SAlexander Aring * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 8b1815fd9SAlexander Aring * GNU General Public License for more details. 9b1815fd9SAlexander Aring * 10b1815fd9SAlexander Aring * Authors: 11b1815fd9SAlexander Aring * (C) 2015 Pengutronix, Alexander Aring <aar@pengutronix.de> 12b1815fd9SAlexander Aring * Copyright (c) 2015 Nordic Semiconductor. All Rights Reserved. 13b1815fd9SAlexander Aring */ 14b1815fd9SAlexander Aring 15b1815fd9SAlexander Aring #include <net/6lowpan.h> 16b1815fd9SAlexander Aring 17b1815fd9SAlexander Aring #include "6lowpan_i.h" 18b1815fd9SAlexander Aring 195609c185SAlexander Aring #define LOWPAN_DEBUGFS_CTX_PFX_NUM_ARGS 8 205609c185SAlexander Aring 21b1815fd9SAlexander Aring static struct dentry *lowpan_debugfs; 22b1815fd9SAlexander Aring 235609c185SAlexander Aring static int lowpan_ctx_flag_active_set(void *data, u64 val) 245609c185SAlexander Aring { 255609c185SAlexander Aring struct lowpan_iphc_ctx *ctx = data; 265609c185SAlexander Aring 275609c185SAlexander Aring if (val != 0 && val != 1) 285609c185SAlexander Aring return -EINVAL; 295609c185SAlexander Aring 305609c185SAlexander Aring if (val) 315609c185SAlexander Aring set_bit(LOWPAN_IPHC_CTX_FLAG_ACTIVE, &ctx->flags); 325609c185SAlexander Aring else 335609c185SAlexander Aring clear_bit(LOWPAN_IPHC_CTX_FLAG_ACTIVE, &ctx->flags); 345609c185SAlexander Aring 355609c185SAlexander Aring return 0; 365609c185SAlexander Aring } 375609c185SAlexander Aring 385609c185SAlexander Aring static int lowpan_ctx_flag_active_get(void *data, u64 *val) 395609c185SAlexander Aring { 405609c185SAlexander Aring *val = lowpan_iphc_ctx_is_active(data); 415609c185SAlexander Aring return 0; 425609c185SAlexander Aring } 435609c185SAlexander Aring 445609c185SAlexander Aring DEFINE_SIMPLE_ATTRIBUTE(lowpan_ctx_flag_active_fops, 455609c185SAlexander Aring lowpan_ctx_flag_active_get, 465609c185SAlexander Aring lowpan_ctx_flag_active_set, "%llu\n"); 475609c185SAlexander Aring 485609c185SAlexander Aring static int lowpan_ctx_flag_c_set(void *data, u64 val) 495609c185SAlexander Aring { 505609c185SAlexander Aring struct lowpan_iphc_ctx *ctx = data; 515609c185SAlexander Aring 525609c185SAlexander Aring if (val != 0 && val != 1) 535609c185SAlexander Aring return -EINVAL; 545609c185SAlexander Aring 555609c185SAlexander Aring if (val) 565609c185SAlexander Aring set_bit(LOWPAN_IPHC_CTX_FLAG_COMPRESSION, &ctx->flags); 575609c185SAlexander Aring else 585609c185SAlexander Aring clear_bit(LOWPAN_IPHC_CTX_FLAG_COMPRESSION, &ctx->flags); 595609c185SAlexander Aring 605609c185SAlexander Aring return 0; 615609c185SAlexander Aring } 625609c185SAlexander Aring 635609c185SAlexander Aring static int lowpan_ctx_flag_c_get(void *data, u64 *val) 645609c185SAlexander Aring { 655609c185SAlexander Aring *val = lowpan_iphc_ctx_is_compression(data); 665609c185SAlexander Aring return 0; 675609c185SAlexander Aring } 685609c185SAlexander Aring 695609c185SAlexander Aring DEFINE_SIMPLE_ATTRIBUTE(lowpan_ctx_flag_c_fops, lowpan_ctx_flag_c_get, 705609c185SAlexander Aring lowpan_ctx_flag_c_set, "%llu\n"); 715609c185SAlexander Aring 725609c185SAlexander Aring static int lowpan_ctx_plen_set(void *data, u64 val) 735609c185SAlexander Aring { 745609c185SAlexander Aring struct lowpan_iphc_ctx *ctx = data; 755609c185SAlexander Aring struct lowpan_iphc_ctx_table *t = 765609c185SAlexander Aring container_of(ctx, struct lowpan_iphc_ctx_table, table[ctx->id]); 775609c185SAlexander Aring 785609c185SAlexander Aring if (val > 128) 795609c185SAlexander Aring return -EINVAL; 805609c185SAlexander Aring 815609c185SAlexander Aring spin_lock_bh(&t->lock); 825609c185SAlexander Aring ctx->plen = val; 835609c185SAlexander Aring spin_unlock_bh(&t->lock); 845609c185SAlexander Aring 855609c185SAlexander Aring return 0; 865609c185SAlexander Aring } 875609c185SAlexander Aring 885609c185SAlexander Aring static int lowpan_ctx_plen_get(void *data, u64 *val) 895609c185SAlexander Aring { 905609c185SAlexander Aring struct lowpan_iphc_ctx *ctx = data; 915609c185SAlexander Aring struct lowpan_iphc_ctx_table *t = 925609c185SAlexander Aring container_of(ctx, struct lowpan_iphc_ctx_table, table[ctx->id]); 935609c185SAlexander Aring 945609c185SAlexander Aring spin_lock_bh(&t->lock); 955609c185SAlexander Aring *val = ctx->plen; 965609c185SAlexander Aring spin_unlock_bh(&t->lock); 975609c185SAlexander Aring return 0; 985609c185SAlexander Aring } 995609c185SAlexander Aring 1005609c185SAlexander Aring DEFINE_SIMPLE_ATTRIBUTE(lowpan_ctx_plen_fops, lowpan_ctx_plen_get, 1015609c185SAlexander Aring lowpan_ctx_plen_set, "%llu\n"); 1025609c185SAlexander Aring 1035609c185SAlexander Aring static int lowpan_ctx_pfx_show(struct seq_file *file, void *offset) 1045609c185SAlexander Aring { 1055609c185SAlexander Aring struct lowpan_iphc_ctx *ctx = file->private; 1065609c185SAlexander Aring struct lowpan_iphc_ctx_table *t = 1075609c185SAlexander Aring container_of(ctx, struct lowpan_iphc_ctx_table, table[ctx->id]); 1085609c185SAlexander Aring 1095609c185SAlexander Aring spin_lock_bh(&t->lock); 1105609c185SAlexander Aring seq_printf(file, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n", 1115609c185SAlexander Aring be16_to_cpu(ctx->pfx.s6_addr16[0]), 1125609c185SAlexander Aring be16_to_cpu(ctx->pfx.s6_addr16[1]), 1135609c185SAlexander Aring be16_to_cpu(ctx->pfx.s6_addr16[2]), 1145609c185SAlexander Aring be16_to_cpu(ctx->pfx.s6_addr16[3]), 1155609c185SAlexander Aring be16_to_cpu(ctx->pfx.s6_addr16[4]), 1165609c185SAlexander Aring be16_to_cpu(ctx->pfx.s6_addr16[5]), 1175609c185SAlexander Aring be16_to_cpu(ctx->pfx.s6_addr16[6]), 1185609c185SAlexander Aring be16_to_cpu(ctx->pfx.s6_addr16[7])); 1195609c185SAlexander Aring spin_unlock_bh(&t->lock); 1205609c185SAlexander Aring 1215609c185SAlexander Aring return 0; 1225609c185SAlexander Aring } 1235609c185SAlexander Aring 1245609c185SAlexander Aring static int lowpan_ctx_pfx_open(struct inode *inode, struct file *file) 1255609c185SAlexander Aring { 1265609c185SAlexander Aring return single_open(file, lowpan_ctx_pfx_show, inode->i_private); 1275609c185SAlexander Aring } 1285609c185SAlexander Aring 1295609c185SAlexander Aring static ssize_t lowpan_ctx_pfx_write(struct file *fp, 1305609c185SAlexander Aring const char __user *user_buf, size_t count, 1315609c185SAlexander Aring loff_t *ppos) 1325609c185SAlexander Aring { 1335609c185SAlexander Aring char buf[128] = {}; 1345609c185SAlexander Aring struct seq_file *file = fp->private_data; 1355609c185SAlexander Aring struct lowpan_iphc_ctx *ctx = file->private; 1365609c185SAlexander Aring struct lowpan_iphc_ctx_table *t = 1375609c185SAlexander Aring container_of(ctx, struct lowpan_iphc_ctx_table, table[ctx->id]); 1385609c185SAlexander Aring int status = count, n, i; 1395609c185SAlexander Aring unsigned int addr[8]; 1405609c185SAlexander Aring 1415609c185SAlexander Aring if (copy_from_user(&buf, user_buf, min_t(size_t, sizeof(buf) - 1, 1425609c185SAlexander Aring count))) { 1435609c185SAlexander Aring status = -EFAULT; 1445609c185SAlexander Aring goto out; 1455609c185SAlexander Aring } 1465609c185SAlexander Aring 1475609c185SAlexander Aring n = sscanf(buf, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x", 1485609c185SAlexander Aring &addr[0], &addr[1], &addr[2], &addr[3], &addr[4], 1495609c185SAlexander Aring &addr[5], &addr[6], &addr[7]); 1505609c185SAlexander Aring if (n != LOWPAN_DEBUGFS_CTX_PFX_NUM_ARGS) { 1515609c185SAlexander Aring status = -EINVAL; 1525609c185SAlexander Aring goto out; 1535609c185SAlexander Aring } 1545609c185SAlexander Aring 1555609c185SAlexander Aring spin_lock_bh(&t->lock); 1565609c185SAlexander Aring for (i = 0; i < 8; i++) 1575609c185SAlexander Aring ctx->pfx.s6_addr16[i] = cpu_to_be16(addr[i] & 0xffff); 1585609c185SAlexander Aring spin_unlock_bh(&t->lock); 1595609c185SAlexander Aring 1605609c185SAlexander Aring out: 1615609c185SAlexander Aring return status; 1625609c185SAlexander Aring } 1635609c185SAlexander Aring 1646aaf37b4SAlexander Aring static const struct file_operations lowpan_ctx_pfx_fops = { 1655609c185SAlexander Aring .open = lowpan_ctx_pfx_open, 1665609c185SAlexander Aring .read = seq_read, 1675609c185SAlexander Aring .write = lowpan_ctx_pfx_write, 1685609c185SAlexander Aring .llseek = seq_lseek, 1695609c185SAlexander Aring .release = single_release, 1705609c185SAlexander Aring }; 1715609c185SAlexander Aring 1725609c185SAlexander Aring static int lowpan_dev_debugfs_ctx_init(struct net_device *dev, 1735609c185SAlexander Aring struct dentry *ctx, u8 id) 1745609c185SAlexander Aring { 175*2e4d60cbSAlexander Aring struct lowpan_dev *ldev = lowpan_dev(dev); 1765609c185SAlexander Aring struct dentry *dentry, *root; 1775609c185SAlexander Aring char buf[32]; 1785609c185SAlexander Aring 1795609c185SAlexander Aring WARN_ON_ONCE(id > LOWPAN_IPHC_CTX_TABLE_SIZE); 1805609c185SAlexander Aring 1815609c185SAlexander Aring sprintf(buf, "%d", id); 1825609c185SAlexander Aring 1835609c185SAlexander Aring root = debugfs_create_dir(buf, ctx); 1845609c185SAlexander Aring if (!root) 1855609c185SAlexander Aring return -EINVAL; 1865609c185SAlexander Aring 1875609c185SAlexander Aring dentry = debugfs_create_file("active", 0644, root, 188*2e4d60cbSAlexander Aring &ldev->ctx.table[id], 1895609c185SAlexander Aring &lowpan_ctx_flag_active_fops); 1905609c185SAlexander Aring if (!dentry) 1915609c185SAlexander Aring return -EINVAL; 1925609c185SAlexander Aring 1935609c185SAlexander Aring dentry = debugfs_create_file("compression", 0644, root, 194*2e4d60cbSAlexander Aring &ldev->ctx.table[id], 1955609c185SAlexander Aring &lowpan_ctx_flag_c_fops); 1965609c185SAlexander Aring if (!dentry) 1975609c185SAlexander Aring return -EINVAL; 1985609c185SAlexander Aring 1995609c185SAlexander Aring dentry = debugfs_create_file("prefix", 0644, root, 200*2e4d60cbSAlexander Aring &ldev->ctx.table[id], 2015609c185SAlexander Aring &lowpan_ctx_pfx_fops); 2025609c185SAlexander Aring if (!dentry) 2035609c185SAlexander Aring return -EINVAL; 2045609c185SAlexander Aring 2055609c185SAlexander Aring dentry = debugfs_create_file("prefix_len", 0644, root, 206*2e4d60cbSAlexander Aring &ldev->ctx.table[id], 2075609c185SAlexander Aring &lowpan_ctx_plen_fops); 2085609c185SAlexander Aring if (!dentry) 2095609c185SAlexander Aring return -EINVAL; 2105609c185SAlexander Aring 2115609c185SAlexander Aring return 0; 2125609c185SAlexander Aring } 2135609c185SAlexander Aring 2145609c185SAlexander Aring static int lowpan_context_show(struct seq_file *file, void *offset) 2155609c185SAlexander Aring { 2165609c185SAlexander Aring struct lowpan_iphc_ctx_table *t = file->private; 2175609c185SAlexander Aring int i; 2185609c185SAlexander Aring 2195609c185SAlexander Aring seq_printf(file, "%3s|%-43s|%c\n", "cid", "prefix", 'C'); 2205609c185SAlexander Aring seq_puts(file, "-------------------------------------------------\n"); 2215609c185SAlexander Aring 2225609c185SAlexander Aring spin_lock_bh(&t->lock); 2235609c185SAlexander Aring for (i = 0; i < LOWPAN_IPHC_CTX_TABLE_SIZE; i++) { 2245609c185SAlexander Aring if (!lowpan_iphc_ctx_is_active(&t->table[i])) 2255609c185SAlexander Aring continue; 2265609c185SAlexander Aring 2275609c185SAlexander Aring seq_printf(file, "%3d|%39pI6c/%-3d|%d\n", t->table[i].id, 2285609c185SAlexander Aring &t->table[i].pfx, t->table[i].plen, 2295609c185SAlexander Aring lowpan_iphc_ctx_is_compression(&t->table[i])); 2305609c185SAlexander Aring } 2315609c185SAlexander Aring spin_unlock_bh(&t->lock); 2325609c185SAlexander Aring 2335609c185SAlexander Aring return 0; 2345609c185SAlexander Aring } 2355609c185SAlexander Aring 2365609c185SAlexander Aring static int lowpan_context_open(struct inode *inode, struct file *file) 2375609c185SAlexander Aring { 2385609c185SAlexander Aring return single_open(file, lowpan_context_show, inode->i_private); 2395609c185SAlexander Aring } 2405609c185SAlexander Aring 2416aaf37b4SAlexander Aring static const struct file_operations lowpan_context_fops = { 2425609c185SAlexander Aring .open = lowpan_context_open, 2435609c185SAlexander Aring .read = seq_read, 2445609c185SAlexander Aring .llseek = seq_lseek, 2455609c185SAlexander Aring .release = single_release, 2465609c185SAlexander Aring }; 2475609c185SAlexander Aring 248b1815fd9SAlexander Aring int lowpan_dev_debugfs_init(struct net_device *dev) 249b1815fd9SAlexander Aring { 250*2e4d60cbSAlexander Aring struct lowpan_dev *ldev = lowpan_dev(dev); 2515609c185SAlexander Aring struct dentry *contexts, *dentry; 2525609c185SAlexander Aring int ret, i; 253b1815fd9SAlexander Aring 254b1815fd9SAlexander Aring /* creating the root */ 255*2e4d60cbSAlexander Aring ldev->iface_debugfs = debugfs_create_dir(dev->name, lowpan_debugfs); 256*2e4d60cbSAlexander Aring if (!ldev->iface_debugfs) 257b1815fd9SAlexander Aring goto fail; 258b1815fd9SAlexander Aring 259*2e4d60cbSAlexander Aring contexts = debugfs_create_dir("contexts", ldev->iface_debugfs); 2605609c185SAlexander Aring if (!contexts) 2615609c185SAlexander Aring goto remove_root; 2625609c185SAlexander Aring 2635609c185SAlexander Aring dentry = debugfs_create_file("show", 0644, contexts, 264*2e4d60cbSAlexander Aring &lowpan_dev(dev)->ctx, 2655609c185SAlexander Aring &lowpan_context_fops); 2665609c185SAlexander Aring if (!dentry) 2675609c185SAlexander Aring goto remove_root; 2685609c185SAlexander Aring 2695609c185SAlexander Aring for (i = 0; i < LOWPAN_IPHC_CTX_TABLE_SIZE; i++) { 2705609c185SAlexander Aring ret = lowpan_dev_debugfs_ctx_init(dev, contexts, i); 2715609c185SAlexander Aring if (ret < 0) 2725609c185SAlexander Aring goto remove_root; 2735609c185SAlexander Aring } 2745609c185SAlexander Aring 275b1815fd9SAlexander Aring return 0; 276b1815fd9SAlexander Aring 2775609c185SAlexander Aring remove_root: 2785609c185SAlexander Aring lowpan_dev_debugfs_exit(dev); 279b1815fd9SAlexander Aring fail: 280b1815fd9SAlexander Aring return -EINVAL; 281b1815fd9SAlexander Aring } 282b1815fd9SAlexander Aring 283b1815fd9SAlexander Aring void lowpan_dev_debugfs_exit(struct net_device *dev) 284b1815fd9SAlexander Aring { 285*2e4d60cbSAlexander Aring debugfs_remove_recursive(lowpan_dev(dev)->iface_debugfs); 286b1815fd9SAlexander Aring } 287b1815fd9SAlexander Aring 288b1815fd9SAlexander Aring int __init lowpan_debugfs_init(void) 289b1815fd9SAlexander Aring { 290b1815fd9SAlexander Aring lowpan_debugfs = debugfs_create_dir("6lowpan", NULL); 291b1815fd9SAlexander Aring if (!lowpan_debugfs) 292b1815fd9SAlexander Aring return -EINVAL; 293b1815fd9SAlexander Aring 294b1815fd9SAlexander Aring return 0; 295b1815fd9SAlexander Aring } 296b1815fd9SAlexander Aring 297b1815fd9SAlexander Aring void lowpan_debugfs_exit(void) 298b1815fd9SAlexander Aring { 299b1815fd9SAlexander Aring debugfs_remove_recursive(lowpan_debugfs); 300b1815fd9SAlexander Aring } 301